mirror of
https://github.com/google/pebble
synced 2026-10-18 01:04:12 +02:00
Import of the watch repository from Pebble
This commit is contained in:
+170
File diff suppressed because one or more lines are too long
+169
File diff suppressed because one or more lines are too long
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
Copyright (c) Thomas Nagy, 2005-2016
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: ISO8859-1
|
||||
# Thomas Nagy, 2005-2012
|
||||
|
||||
"""
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
|
||||
VERSION="1.7.11"
|
||||
REVISION="x"
|
||||
INSTALL="x"
|
||||
C1='x'
|
||||
C2='x'
|
||||
cwd = os.getcwd()
|
||||
join = os.path.join
|
||||
|
||||
if sys.hexversion<0x206000f:
|
||||
raise ImportError('Python >= 2.6 is required to create the waf file')
|
||||
|
||||
WAF='waf'
|
||||
def b(x):
|
||||
return x
|
||||
if sys.hexversion>0x300000f:
|
||||
WAF='waf3'
|
||||
def b(x):
|
||||
return x.encode()
|
||||
|
||||
def err(m):
|
||||
print(('\033[91mError: %s\033[0m' % m))
|
||||
sys.exit(1)
|
||||
|
||||
def unpack_wafdir(dir):
|
||||
f = open(sys.argv[0],'rb')
|
||||
c = 'corrupt archive (%d)'
|
||||
while 1:
|
||||
line = f.readline()
|
||||
if not line: err('run waf-light from a folder containing waflib')
|
||||
if line == b('#==>\n'):
|
||||
txt = f.readline()
|
||||
if not txt: err(c % 1)
|
||||
if f.readline() != b('#<==\n'): err(c % 2)
|
||||
break
|
||||
if not txt: err(c % 3)
|
||||
txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r'))
|
||||
|
||||
import shutil, tarfile
|
||||
try: shutil.rmtree(dir)
|
||||
except OSError: pass
|
||||
try:
|
||||
for x in ['Tools', 'extras']:
|
||||
os.makedirs(join(dir, 'waflib', x))
|
||||
except OSError:
|
||||
err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir)
|
||||
|
||||
os.chdir(dir)
|
||||
tmp = 't.bz2'
|
||||
t = open(tmp,'wb')
|
||||
try: t.write(txt)
|
||||
finally: t.close()
|
||||
|
||||
try:
|
||||
t = tarfile.open(tmp)
|
||||
except:
|
||||
try:
|
||||
os.system('bunzip2 t.bz2')
|
||||
t = tarfile.open('t')
|
||||
tmp = 't'
|
||||
except:
|
||||
os.chdir(cwd)
|
||||
try: shutil.rmtree(dir)
|
||||
except OSError: pass
|
||||
err("Waf cannot be unpacked, check that bzip2 support is present")
|
||||
|
||||
try:
|
||||
for x in t: t.extract(x)
|
||||
finally:
|
||||
t.close()
|
||||
|
||||
for x in ['Tools', 'extras']:
|
||||
os.chmod(join('waflib',x), 493)
|
||||
|
||||
if sys.hexversion<0x300000f:
|
||||
sys.path = [join(dir, 'waflib')] + sys.path
|
||||
import fixpy2
|
||||
fixpy2.fixdir(dir)
|
||||
|
||||
os.remove(tmp)
|
||||
os.chdir(cwd)
|
||||
|
||||
try: dir = unicode(dir, 'mbcs')
|
||||
except: pass
|
||||
try:
|
||||
from ctypes import windll
|
||||
windll.kernel32.SetFileAttributesW(dir, 2)
|
||||
except:
|
||||
pass
|
||||
|
||||
def test(dir):
|
||||
try:
|
||||
os.stat(join(dir, 'waflib'))
|
||||
return os.path.abspath(dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def find_lib():
|
||||
name = sys.argv[0]
|
||||
base = os.path.dirname(os.path.abspath(name))
|
||||
|
||||
#devs use $WAFDIR
|
||||
w=test(os.environ.get('WAFDIR', ''))
|
||||
if w: return w
|
||||
|
||||
#waf-light
|
||||
if name.endswith('waf-light'):
|
||||
w = test(base)
|
||||
if w: return w
|
||||
err('waf-light requires waflib -> export WAFDIR=/folder')
|
||||
|
||||
dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)
|
||||
for i in [INSTALL,'/usr','/usr/local','/opt']:
|
||||
w = test(i + '/lib/' + dirname)
|
||||
if w: return w
|
||||
|
||||
#waf-local
|
||||
dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)
|
||||
w = test(dir)
|
||||
if w: return w
|
||||
|
||||
#unpack
|
||||
unpack_wafdir(dir)
|
||||
return dir
|
||||
|
||||
wafdir = find_lib()
|
||||
sys.path.insert(0, wafdir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
#import waflib.extras.compat15#PRELUDE
|
||||
from waflib import Scripting
|
||||
Scripting.waf_entry_point(cwd, VERSION, wafdir)
|
||||
|
||||
+1350
File diff suppressed because it is too large
Load Diff
+342
@@ -0,0 +1,342 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
|
||||
ConfigSet: a special dict
|
||||
|
||||
The values put in :py:class:`ConfigSet` must be lists
|
||||
"""
|
||||
|
||||
import copy, re, os
|
||||
from waflib import Logs, Utils
|
||||
re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)
|
||||
|
||||
class ConfigSet(object):
|
||||
"""
|
||||
A dict that honor serialization and parent relationships. The serialization format
|
||||
is human-readable (python-like) and performed by using eval() and repr().
|
||||
For high performance prefer pickle. Do not store functions as they are not serializable.
|
||||
|
||||
The values can be accessed by attributes or by keys::
|
||||
|
||||
from waflib.ConfigSet import ConfigSet
|
||||
env = ConfigSet()
|
||||
env.FOO = 'test'
|
||||
env['FOO'] = 'test'
|
||||
"""
|
||||
__slots__ = ('table', 'parent')
|
||||
def __init__(self, filename=None):
|
||||
self.table = {}
|
||||
"""
|
||||
Internal dict holding the object values
|
||||
"""
|
||||
#self.parent = None
|
||||
|
||||
if filename:
|
||||
self.load(filename)
|
||||
|
||||
def __contains__(self, key):
|
||||
"""
|
||||
Enable the *in* syntax::
|
||||
|
||||
if 'foo' in env:
|
||||
print(env['foo'])
|
||||
"""
|
||||
if key in self.table: return True
|
||||
try: return self.parent.__contains__(key)
|
||||
except AttributeError: return False # parent may not exist
|
||||
|
||||
def keys(self):
|
||||
"""Dict interface (unknown purpose)"""
|
||||
keys = set()
|
||||
cur = self
|
||||
while cur:
|
||||
keys.update(cur.table.keys())
|
||||
cur = getattr(cur, 'parent', None)
|
||||
keys = list(keys)
|
||||
keys.sort()
|
||||
return keys
|
||||
|
||||
def __str__(self):
|
||||
"""Text representation of the ConfigSet (for debugging purposes)"""
|
||||
return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in self.keys()])
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
Dictionary interface: get value from key::
|
||||
|
||||
def configure(conf):
|
||||
conf.env['foo'] = {}
|
||||
print(env['foo'])
|
||||
"""
|
||||
try:
|
||||
while 1:
|
||||
x = self.table.get(key, None)
|
||||
if not x is None:
|
||||
return x
|
||||
self = self.parent
|
||||
except AttributeError:
|
||||
return []
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""
|
||||
Dictionary interface: get value from key
|
||||
"""
|
||||
self.table[key] = value
|
||||
|
||||
def __delitem__(self, key):
|
||||
"""
|
||||
Dictionary interface: get value from key
|
||||
"""
|
||||
self[key] = []
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
Attribute access provided for convenience. The following forms are equivalent::
|
||||
|
||||
def configure(conf):
|
||||
conf.env.value
|
||||
conf.env['value']
|
||||
"""
|
||||
if name in self.__slots__:
|
||||
return object.__getattr__(self, name)
|
||||
else:
|
||||
return self[name]
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
"""
|
||||
Attribute access provided for convenience. The following forms are equivalent::
|
||||
|
||||
def configure(conf):
|
||||
conf.env.value = x
|
||||
env['value'] = x
|
||||
"""
|
||||
if name in self.__slots__:
|
||||
object.__setattr__(self, name, value)
|
||||
else:
|
||||
self[name] = value
|
||||
|
||||
def __delattr__(self, name):
|
||||
"""
|
||||
Attribute access provided for convenience. The following forms are equivalent::
|
||||
|
||||
def configure(conf):
|
||||
del env.value
|
||||
del env['value']
|
||||
"""
|
||||
if name in self.__slots__:
|
||||
object.__delattr__(self, name)
|
||||
else:
|
||||
del self[name]
|
||||
|
||||
def derive(self):
|
||||
"""
|
||||
Returns a new ConfigSet deriving from self. The copy returned
|
||||
will be a shallow copy::
|
||||
|
||||
from waflib.ConfigSet import ConfigSet
|
||||
env = ConfigSet()
|
||||
env.append_value('CFLAGS', ['-O2'])
|
||||
child = env.derive()
|
||||
child.CFLAGS.append('test') # warning! this will modify 'env'
|
||||
child.CFLAGS = ['-O3'] # new list, ok
|
||||
child.append_value('CFLAGS', ['-O3']) # ok
|
||||
|
||||
Use :py:func:`ConfigSet.detach` to detach the child from the parent.
|
||||
"""
|
||||
newenv = ConfigSet()
|
||||
newenv.parent = self
|
||||
return newenv
|
||||
|
||||
def detach(self):
|
||||
"""
|
||||
Detach self from its parent (if existing)
|
||||
|
||||
Modifying the parent :py:class:`ConfigSet` will not change the current object
|
||||
Modifying this :py:class:`ConfigSet` will not modify the parent one.
|
||||
"""
|
||||
tbl = self.get_merged_dict()
|
||||
try:
|
||||
delattr(self, 'parent')
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
keys = tbl.keys()
|
||||
for x in keys:
|
||||
tbl[x] = copy.deepcopy(tbl[x])
|
||||
self.table = tbl
|
||||
|
||||
def get_flat(self, key):
|
||||
"""
|
||||
Return a value as a string. If the input is a list, the value returned is space-separated.
|
||||
|
||||
:param key: key to use
|
||||
:type key: string
|
||||
"""
|
||||
s = self[key]
|
||||
if isinstance(s, str): return s
|
||||
return ' '.join(s)
|
||||
|
||||
def _get_list_value_for_modification(self, key):
|
||||
"""
|
||||
Return a list value for further modification.
|
||||
|
||||
The list may be modified inplace and there is no need to do this afterwards::
|
||||
|
||||
self.table[var] = value
|
||||
"""
|
||||
try:
|
||||
value = self.table[key]
|
||||
except KeyError:
|
||||
try: value = self.parent[key]
|
||||
except AttributeError: value = []
|
||||
if isinstance(value, list):
|
||||
value = value[:]
|
||||
else:
|
||||
value = [value]
|
||||
else:
|
||||
if not isinstance(value, list):
|
||||
value = [value]
|
||||
self.table[key] = value
|
||||
return value
|
||||
|
||||
def append_value(self, var, val):
|
||||
"""
|
||||
Appends a value to the specified config key::
|
||||
|
||||
def build(bld):
|
||||
bld.env.append_value('CFLAGS', ['-O2'])
|
||||
|
||||
The value must be a list or a tuple
|
||||
"""
|
||||
current_value = self._get_list_value_for_modification(var)
|
||||
if isinstance(val, str): # if there were string everywhere we could optimize this
|
||||
val = [val]
|
||||
current_value.extend(val)
|
||||
|
||||
def prepend_value(self, var, val):
|
||||
"""
|
||||
Prepends a value to the specified item::
|
||||
|
||||
def configure(conf):
|
||||
conf.env.prepend_value('CFLAGS', ['-O2'])
|
||||
|
||||
The value must be a list or a tuple
|
||||
"""
|
||||
if isinstance(val, str):
|
||||
val = [val]
|
||||
self.table[var] = val + self._get_list_value_for_modification(var)
|
||||
|
||||
def append_unique(self, var, val):
|
||||
"""
|
||||
Append a value to the specified item only if it's not already present::
|
||||
|
||||
def build(bld):
|
||||
bld.env.append_unique('CFLAGS', ['-O2', '-g'])
|
||||
|
||||
The value must be a list or a tuple
|
||||
"""
|
||||
if isinstance(val, str):
|
||||
val = [val]
|
||||
current_value = self._get_list_value_for_modification(var)
|
||||
|
||||
for x in val:
|
||||
if x not in current_value:
|
||||
current_value.append(x)
|
||||
|
||||
def get_merged_dict(self):
|
||||
"""
|
||||
Compute the merged dictionary from the fusion of self and all its parent
|
||||
|
||||
:rtype: a ConfigSet object
|
||||
"""
|
||||
table_list = []
|
||||
env = self
|
||||
while 1:
|
||||
table_list.insert(0, env.table)
|
||||
try: env = env.parent
|
||||
except AttributeError: break
|
||||
merged_table = {}
|
||||
for table in table_list:
|
||||
merged_table.update(table)
|
||||
return merged_table
|
||||
|
||||
def store(self, filename):
|
||||
"""
|
||||
Write the :py:class:`ConfigSet` data into a file. See :py:meth:`ConfigSet.load` for reading such files.
|
||||
|
||||
:param filename: file to use
|
||||
:type filename: string
|
||||
"""
|
||||
try:
|
||||
os.makedirs(os.path.split(filename)[0])
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
buf = []
|
||||
merged_table = self.get_merged_dict()
|
||||
keys = list(merged_table.keys())
|
||||
keys.sort()
|
||||
|
||||
try:
|
||||
fun = ascii
|
||||
except NameError:
|
||||
fun = repr
|
||||
|
||||
for k in keys:
|
||||
if k != 'undo_stack':
|
||||
buf.append('%s = %s\n' % (k, fun(merged_table[k])))
|
||||
Utils.writef(filename, ''.join(buf))
|
||||
|
||||
def load(self, filename):
|
||||
"""
|
||||
Retrieve the :py:class:`ConfigSet` data from a file. See :py:meth:`ConfigSet.store` for writing such files
|
||||
|
||||
:param filename: file to use
|
||||
:type filename: string
|
||||
"""
|
||||
tbl = self.table
|
||||
code = Utils.readf(filename, m='rU')
|
||||
for m in re_imp.finditer(code):
|
||||
g = m.group
|
||||
tbl[g(2)] = eval(g(3))
|
||||
Logs.debug('env: %s' % str(self.table))
|
||||
|
||||
def update(self, d):
|
||||
"""
|
||||
Dictionary interface: replace values from another dict
|
||||
|
||||
:param d: object to use the value from
|
||||
:type d: dict-like object
|
||||
"""
|
||||
for k, v in d.items():
|
||||
self[k] = v
|
||||
|
||||
def stash(self):
|
||||
"""
|
||||
Store the object state, to provide a kind of transaction support::
|
||||
|
||||
env = ConfigSet()
|
||||
env.stash()
|
||||
try:
|
||||
env.append_value('CFLAGS', '-O3')
|
||||
call_some_method(env)
|
||||
finally:
|
||||
env.revert()
|
||||
|
||||
The history is kept in a stack, and is lost during the serialization by :py:meth:`ConfigSet.store`
|
||||
"""
|
||||
orig = self.table
|
||||
tbl = self.table = self.table.copy()
|
||||
for x in tbl.keys():
|
||||
tbl[x] = copy.deepcopy(tbl[x])
|
||||
self.undo_stack = self.undo_stack + [orig]
|
||||
|
||||
def revert(self):
|
||||
"""
|
||||
Reverts the object to a previous state. See :py:meth:`ConfigSet.stash`
|
||||
"""
|
||||
self.table = self.undo_stack.pop(-1)
|
||||
|
||||
+572
@@ -0,0 +1,572 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
Configuration system
|
||||
|
||||
A :py:class:`waflib.Configure.ConfigurationContext` instance is created when ``waf configure`` is called, it is used to:
|
||||
|
||||
* create data dictionaries (ConfigSet instances)
|
||||
* store the list of modules to import
|
||||
* hold configuration routines such as ``find_program``, etc
|
||||
"""
|
||||
|
||||
import os, shlex, sys, time
|
||||
from waflib import ConfigSet, Utils, Options, Logs, Context, Build, Errors
|
||||
|
||||
try:
|
||||
from urllib import request
|
||||
except ImportError:
|
||||
from urllib import urlopen
|
||||
else:
|
||||
urlopen = request.urlopen
|
||||
|
||||
BREAK = 'break'
|
||||
"""In case of a configuration error, break"""
|
||||
|
||||
CONTINUE = 'continue'
|
||||
"""In case of a configuration error, continue"""
|
||||
|
||||
WAF_CONFIG_LOG = 'config.log'
|
||||
"""Name of the configuration log file"""
|
||||
|
||||
autoconfig = False
|
||||
"""Execute the configuration automatically"""
|
||||
|
||||
conf_template = '''# project %(app)s configured on %(now)s by
|
||||
# waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s)
|
||||
# using %(args)s
|
||||
#'''
|
||||
|
||||
def download_check(node):
|
||||
"""
|
||||
Hook to check for the tools which are downloaded. Replace with your function if necessary.
|
||||
"""
|
||||
pass
|
||||
|
||||
def download_tool(tool, force=False, ctx=None):
|
||||
"""
|
||||
Download a Waf tool from the remote repository defined in :py:const:`waflib.Context.remote_repo`::
|
||||
|
||||
$ waf configure --download
|
||||
"""
|
||||
for x in Utils.to_list(Context.remote_repo):
|
||||
for sub in Utils.to_list(Context.remote_locs):
|
||||
url = '/'.join((x, sub, tool + '.py'))
|
||||
try:
|
||||
web = urlopen(url)
|
||||
try:
|
||||
if web.getcode() != 200:
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
except Exception:
|
||||
# on python3 urlopen throws an exception
|
||||
# python 2.3 does not have getcode and throws an exception to fail
|
||||
continue
|
||||
else:
|
||||
tmp = ctx.root.make_node(os.sep.join((Context.waf_dir, 'waflib', 'extras', tool + '.py')))
|
||||
tmp.write(web.read(), 'wb')
|
||||
Logs.warn('Downloaded %s from %s' % (tool, url))
|
||||
download_check(tmp)
|
||||
try:
|
||||
module = Context.load_tool(tool)
|
||||
except Exception:
|
||||
Logs.warn('The tool %s from %s is unusable' % (tool, url))
|
||||
try:
|
||||
tmp.delete()
|
||||
except Exception:
|
||||
pass
|
||||
continue
|
||||
return module
|
||||
raise Errors.WafError('Could not load the Waf tool')
|
||||
|
||||
class ConfigurationContext(Context.Context):
|
||||
'''configures the project'''
|
||||
|
||||
cmd = 'configure'
|
||||
|
||||
error_handlers = []
|
||||
"""
|
||||
Additional functions to handle configuration errors
|
||||
"""
|
||||
|
||||
def __init__(self, **kw):
|
||||
super(ConfigurationContext, self).__init__(**kw)
|
||||
self.environ = dict(os.environ)
|
||||
self.all_envs = {}
|
||||
|
||||
self.top_dir = None
|
||||
self.out_dir = None
|
||||
|
||||
self.tools = [] # tools loaded in the configuration, and that will be loaded when building
|
||||
|
||||
self.hash = 0
|
||||
self.files = []
|
||||
|
||||
self.tool_cache = []
|
||||
|
||||
self.setenv('')
|
||||
|
||||
def setenv(self, name, env=None):
|
||||
"""
|
||||
Set a new config set for conf.env. If a config set of that name already exists,
|
||||
recall it without modification.
|
||||
|
||||
The name is the filename prefix to save to ``c4che/NAME_cache.py``, and it
|
||||
is also used as *variants* by the build commands.
|
||||
Though related to variants, whatever kind of data may be stored in the config set::
|
||||
|
||||
def configure(cfg):
|
||||
cfg.env.ONE = 1
|
||||
cfg.setenv('foo')
|
||||
cfg.env.ONE = 2
|
||||
|
||||
def build(bld):
|
||||
2 == bld.env_of_name('foo').ONE
|
||||
|
||||
:param name: name of the configuration set
|
||||
:type name: string
|
||||
:param env: ConfigSet to copy, or an empty ConfigSet is created
|
||||
:type env: :py:class:`waflib.ConfigSet.ConfigSet`
|
||||
"""
|
||||
if name not in self.all_envs or env:
|
||||
if not env:
|
||||
env = ConfigSet.ConfigSet()
|
||||
self.prepare_env(env)
|
||||
else:
|
||||
env = env.derive()
|
||||
self.all_envs[name] = env
|
||||
self.variant = name
|
||||
|
||||
def get_env(self):
|
||||
"""Getter for the env property"""
|
||||
return self.all_envs[self.variant]
|
||||
def set_env(self, val):
|
||||
"""Setter for the env property"""
|
||||
self.all_envs[self.variant] = val
|
||||
|
||||
env = property(get_env, set_env)
|
||||
|
||||
def init_dirs(self):
|
||||
"""
|
||||
Initialize the project directory and the build directory
|
||||
"""
|
||||
|
||||
top = self.top_dir
|
||||
if not top:
|
||||
top = Options.options.top
|
||||
if not top:
|
||||
top = getattr(Context.g_module, Context.TOP, None)
|
||||
if not top:
|
||||
top = self.path.abspath()
|
||||
top = os.path.abspath(top)
|
||||
|
||||
self.srcnode = (os.path.isabs(top) and self.root or self.path).find_dir(top)
|
||||
assert(self.srcnode)
|
||||
|
||||
out = self.out_dir
|
||||
if not out:
|
||||
out = Options.options.out
|
||||
if not out:
|
||||
out = getattr(Context.g_module, Context.OUT, None)
|
||||
if not out:
|
||||
out = Options.lockfile.replace('.lock-waf_%s_' % sys.platform, '').replace('.lock-waf', '')
|
||||
|
||||
self.bldnode = (os.path.isabs(out) and self.root or self.path).make_node(out)
|
||||
self.bldnode.mkdir()
|
||||
|
||||
if not os.path.isdir(self.bldnode.abspath()):
|
||||
conf.fatal('Could not create the build directory %s' % self.bldnode.abspath())
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
See :py:func:`waflib.Context.Context.execute`
|
||||
"""
|
||||
self.init_dirs()
|
||||
|
||||
self.cachedir = self.bldnode.make_node(Build.CACHE_DIR)
|
||||
self.cachedir.mkdir()
|
||||
|
||||
path = os.path.join(self.bldnode.abspath(), WAF_CONFIG_LOG)
|
||||
self.logger = Logs.make_logger(path, 'cfg')
|
||||
|
||||
app = getattr(Context.g_module, 'APPNAME', '')
|
||||
if app:
|
||||
ver = getattr(Context.g_module, 'VERSION', '')
|
||||
if ver:
|
||||
app = "%s (%s)" % (app, ver)
|
||||
|
||||
now = time.ctime()
|
||||
pyver = sys.hexversion
|
||||
systype = sys.platform
|
||||
args = " ".join(sys.argv)
|
||||
wafver = Context.WAFVERSION
|
||||
abi = Context.ABI
|
||||
self.to_log(conf_template % vars())
|
||||
|
||||
self.msg('Setting top to', self.srcnode.abspath())
|
||||
self.msg('Setting out to', self.bldnode.abspath())
|
||||
|
||||
if id(self.srcnode) == id(self.bldnode):
|
||||
Logs.warn('Setting top == out (remember to use "update_outputs")')
|
||||
elif id(self.path) != id(self.srcnode):
|
||||
if self.srcnode.is_child_of(self.path):
|
||||
Logs.warn('Are you certain that you do not want to set top="." ?')
|
||||
|
||||
super(ConfigurationContext, self).execute()
|
||||
|
||||
self.store()
|
||||
|
||||
Context.top_dir = self.srcnode.abspath()
|
||||
Context.out_dir = self.bldnode.abspath()
|
||||
|
||||
# this will write a configure lock so that subsequent builds will
|
||||
# consider the current path as the root directory (see prepare_impl).
|
||||
# to remove: use 'waf distclean'
|
||||
env = ConfigSet.ConfigSet()
|
||||
env['argv'] = sys.argv
|
||||
env['options'] = Options.options.__dict__
|
||||
|
||||
env.run_dir = Context.run_dir
|
||||
env.top_dir = Context.top_dir
|
||||
env.out_dir = Context.out_dir
|
||||
|
||||
# conf.hash & conf.files hold wscript files paths and hash
|
||||
# (used only by Configure.autoconfig)
|
||||
env['hash'] = self.hash
|
||||
env['files'] = self.files
|
||||
env['environ'] = dict(self.environ)
|
||||
|
||||
if not self.env.NO_LOCK_IN_RUN:
|
||||
env.store(Context.run_dir + os.sep + Options.lockfile)
|
||||
if not self.env.NO_LOCK_IN_TOP:
|
||||
env.store(Context.top_dir + os.sep + Options.lockfile)
|
||||
if not self.env.NO_LOCK_IN_OUT:
|
||||
env.store(Context.out_dir + os.sep + Options.lockfile)
|
||||
|
||||
def prepare_env(self, env):
|
||||
"""
|
||||
Insert *PREFIX*, *BINDIR* and *LIBDIR* values into ``env``
|
||||
|
||||
:type env: :py:class:`waflib.ConfigSet.ConfigSet`
|
||||
:param env: a ConfigSet, usually ``conf.env``
|
||||
"""
|
||||
if not env.PREFIX:
|
||||
if Options.options.prefix or Utils.is_win32:
|
||||
env.PREFIX = os.path.abspath(os.path.expanduser(Options.options.prefix))
|
||||
else:
|
||||
env.PREFIX = ''
|
||||
if not env.BINDIR:
|
||||
env.BINDIR = Utils.subst_vars('${PREFIX}/bin', env)
|
||||
if not env.LIBDIR:
|
||||
env.LIBDIR = Utils.subst_vars('${PREFIX}/lib', env)
|
||||
|
||||
def store(self):
|
||||
"""Save the config results into the cache file"""
|
||||
n = self.cachedir.make_node('build.config.py')
|
||||
n.write('version = 0x%x\ntools = %r\n' % (Context.HEXVERSION, self.tools))
|
||||
|
||||
if not self.all_envs:
|
||||
self.fatal('nothing to store in the configuration context!')
|
||||
|
||||
for key in self.all_envs:
|
||||
tmpenv = self.all_envs[key]
|
||||
tmpenv.store(os.path.join(self.cachedir.abspath(), key + Build.CACHE_SUFFIX))
|
||||
|
||||
def load(self, input, tooldir=None, funs=None, download=True):
|
||||
"""
|
||||
Load Waf tools, which will be imported whenever a build is started.
|
||||
|
||||
:param input: waf tools to import
|
||||
:type input: list of string
|
||||
:param tooldir: paths for the imports
|
||||
:type tooldir: list of string
|
||||
:param funs: functions to execute from the waf tools
|
||||
:type funs: list of string
|
||||
:param download: whether to download the tool from the waf repository
|
||||
:type download: bool
|
||||
"""
|
||||
|
||||
tools = Utils.to_list(input)
|
||||
if tooldir: tooldir = Utils.to_list(tooldir)
|
||||
for tool in tools:
|
||||
# avoid loading the same tool more than once with the same functions
|
||||
# used by composite projects
|
||||
|
||||
mag = (tool, id(self.env), funs)
|
||||
if mag in self.tool_cache:
|
||||
self.to_log('(tool %s is already loaded, skipping)' % tool)
|
||||
continue
|
||||
self.tool_cache.append(mag)
|
||||
|
||||
module = None
|
||||
try:
|
||||
module = Context.load_tool(tool, tooldir)
|
||||
except ImportError as e:
|
||||
if Options.options.download:
|
||||
module = download_tool(tool, ctx=self)
|
||||
if not module:
|
||||
self.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s' % (tool, sys.path, e))
|
||||
else:
|
||||
self.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s' % (tool, sys.path, e))
|
||||
except Exception as e:
|
||||
self.to_log('imp %r (%r & %r)' % (tool, tooldir, funs))
|
||||
self.to_log(Utils.ex_stack())
|
||||
raise
|
||||
|
||||
if funs is not None:
|
||||
self.eval_rules(funs)
|
||||
else:
|
||||
func = getattr(module, 'configure', None)
|
||||
if func:
|
||||
if type(func) is type(Utils.readf): func(self)
|
||||
else: self.eval_rules(func)
|
||||
|
||||
self.tools.append({'tool':tool, 'tooldir':tooldir, 'funs':funs})
|
||||
|
||||
def post_recurse(self, node):
|
||||
"""
|
||||
Records the path and a hash of the scripts visited, see :py:meth:`waflib.Context.Context.post_recurse`
|
||||
|
||||
:param node: script
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
super(ConfigurationContext, self).post_recurse(node)
|
||||
self.hash = hash((self.hash, node.read('rb')))
|
||||
self.files.append(node.abspath())
|
||||
|
||||
def eval_rules(self, rules):
|
||||
"""
|
||||
Execute the configuration tests. The method :py:meth:`waflib.Configure.ConfigurationContext.err_handler`
|
||||
is used to process the eventual exceptions
|
||||
|
||||
:param rules: list of configuration method names
|
||||
:type rules: list of string
|
||||
"""
|
||||
self.rules = Utils.to_list(rules)
|
||||
for x in self.rules:
|
||||
f = getattr(self, x)
|
||||
if not f: self.fatal("No such method '%s'." % x)
|
||||
try:
|
||||
f()
|
||||
except Exception as e:
|
||||
ret = self.err_handler(x, e)
|
||||
if ret == BREAK:
|
||||
break
|
||||
elif ret == CONTINUE:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
def err_handler(self, fun, error):
|
||||
"""
|
||||
Error handler for the configuration tests, the default is to let the exception raise
|
||||
|
||||
:param fun: configuration test
|
||||
:type fun: method
|
||||
:param error: exception
|
||||
:type error: exception
|
||||
"""
|
||||
pass
|
||||
|
||||
def conf(f):
|
||||
"""
|
||||
Decorator: attach new configuration functions to :py:class:`waflib.Build.BuildContext` and
|
||||
:py:class:`waflib.Configure.ConfigurationContext`. The methods bound will accept a parameter
|
||||
named 'mandatory' to disable the configuration errors::
|
||||
|
||||
def configure(conf):
|
||||
conf.find_program('abc', mandatory=False)
|
||||
|
||||
:param f: method to bind
|
||||
:type f: function
|
||||
"""
|
||||
def fun(*k, **kw):
|
||||
mandatory = True
|
||||
if 'mandatory' in kw:
|
||||
mandatory = kw['mandatory']
|
||||
del kw['mandatory']
|
||||
|
||||
try:
|
||||
return f(*k, **kw)
|
||||
except Errors.ConfigurationError:
|
||||
if mandatory:
|
||||
raise
|
||||
|
||||
setattr(ConfigurationContext, f.__name__, fun)
|
||||
setattr(Build.BuildContext, f.__name__, fun)
|
||||
return f
|
||||
|
||||
@conf
|
||||
def add_os_flags(self, var, dest=None):
|
||||
"""
|
||||
Import operating system environment values into ``conf.env`` dict::
|
||||
|
||||
def configure(conf):
|
||||
conf.add_os_flags('CFLAGS')
|
||||
|
||||
:param var: variable to use
|
||||
:type var: string
|
||||
:param dest: destination variable, by default the same as var
|
||||
:type dest: string
|
||||
"""
|
||||
# do not use 'get' to make certain the variable is not defined
|
||||
try: self.env.append_value(dest or var, shlex.split(self.environ[var]))
|
||||
except KeyError: pass
|
||||
|
||||
@conf
|
||||
def cmd_to_list(self, cmd):
|
||||
"""
|
||||
Detect if a command is written in pseudo shell like ``ccache g++`` and return a list.
|
||||
|
||||
:param cmd: command
|
||||
:type cmd: a string or a list of string
|
||||
"""
|
||||
if isinstance(cmd, str) and cmd.find(' '):
|
||||
try:
|
||||
os.stat(cmd)
|
||||
except OSError:
|
||||
return shlex.split(cmd)
|
||||
else:
|
||||
return [cmd]
|
||||
return cmd
|
||||
|
||||
@conf
|
||||
def check_waf_version(self, mini='1.6.99', maxi='1.8.0'):
|
||||
"""
|
||||
Raise a Configuration error if the Waf version does not strictly match the given bounds::
|
||||
|
||||
conf.check_waf_version(mini='1.7.0', maxi='1.8.0')
|
||||
|
||||
:type mini: number, tuple or string
|
||||
:param mini: Minimum required version
|
||||
:type maxi: number, tuple or string
|
||||
:param maxi: Maximum allowed version
|
||||
"""
|
||||
self.start_msg('Checking for waf version in %s-%s' % (str(mini), str(maxi)))
|
||||
ver = Context.HEXVERSION
|
||||
if Utils.num2ver(mini) > ver:
|
||||
self.fatal('waf version should be at least %r (%r found)' % (Utils.num2ver(mini), ver))
|
||||
|
||||
if Utils.num2ver(maxi) < ver:
|
||||
self.fatal('waf version should be at most %r (%r found)' % (Utils.num2ver(maxi), ver))
|
||||
self.end_msg('ok')
|
||||
|
||||
@conf
|
||||
def find_file(self, filename, path_list=[]):
|
||||
"""
|
||||
Find a file in a list of paths
|
||||
|
||||
:param filename: name of the file to search for
|
||||
:param path_list: list of directories to search
|
||||
:return: the first occurrence filename or '' if filename could not be found
|
||||
"""
|
||||
for n in Utils.to_list(filename):
|
||||
for d in Utils.to_list(path_list):
|
||||
p = os.path.join(d, n)
|
||||
if os.path.exists(p):
|
||||
return p
|
||||
self.fatal('Could not find %r' % filename)
|
||||
|
||||
@conf
|
||||
def find_program(self, filename, **kw):
|
||||
"""
|
||||
Search for a program on the operating system
|
||||
|
||||
When var is used, you may set os.environ[var] to help find a specific program version, for example::
|
||||
|
||||
$ VALAC=/usr/bin/valac_test waf configure
|
||||
|
||||
:param path_list: paths to use for searching
|
||||
:type param_list: list of string
|
||||
:param var: store the result to conf.env[var], by default use filename.upper()
|
||||
:type var: string
|
||||
:param ext: list of extensions for the binary (do not add an extension for portability)
|
||||
:type ext: list of string
|
||||
"""
|
||||
|
||||
exts = kw.get('exts', Utils.is_win32 and '.exe,.com,.bat,.cmd' or ',.sh,.pl,.py')
|
||||
|
||||
environ = kw.get('environ', os.environ)
|
||||
|
||||
ret = ''
|
||||
filename = Utils.to_list(filename)
|
||||
|
||||
var = kw.get('var', '')
|
||||
if not var:
|
||||
var = filename[0].upper()
|
||||
|
||||
if self.env[var]:
|
||||
ret = self.env[var]
|
||||
elif var in environ:
|
||||
ret = environ[var]
|
||||
|
||||
path_list = kw.get('path_list', '')
|
||||
if not ret:
|
||||
if path_list:
|
||||
path_list = Utils.to_list(path_list)
|
||||
else:
|
||||
path_list = environ.get('PATH', '').split(os.pathsep)
|
||||
|
||||
if not isinstance(filename, list):
|
||||
filename = [filename]
|
||||
|
||||
for a in exts.split(','):
|
||||
if ret:
|
||||
break
|
||||
for b in filename:
|
||||
if ret:
|
||||
break
|
||||
for c in path_list:
|
||||
if ret:
|
||||
break
|
||||
x = os.path.expanduser(os.path.join(c, b + a))
|
||||
if os.path.isfile(x):
|
||||
ret = x
|
||||
|
||||
if not ret and Utils.winreg:
|
||||
ret = Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER, filename)
|
||||
if not ret and Utils.winreg:
|
||||
ret = Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE, filename)
|
||||
|
||||
self.msg('Checking for program ' + ','.join(filename), ret or False)
|
||||
self.to_log('find program=%r paths=%r var=%r -> %r' % (filename, path_list, var, ret))
|
||||
|
||||
if not ret:
|
||||
self.fatal(kw.get('errmsg', '') or 'Could not find the program %s' % ','.join(filename))
|
||||
|
||||
if var:
|
||||
self.env[var] = ret
|
||||
return ret
|
||||
|
||||
|
||||
@conf
|
||||
def find_perl_program(self, filename, path_list=[], var=None, environ=None, exts=''):
|
||||
"""
|
||||
Search for a perl program on the operating system
|
||||
|
||||
:param filename: file to search for
|
||||
:type filename: string
|
||||
:param path_list: list of paths to look into
|
||||
:type path_list: list of string
|
||||
:param var: store the results into *conf.env.var*
|
||||
:type var: string
|
||||
:param environ: operating system environment to pass to :py:func:`waflib.Configure.find_program`
|
||||
:type environ: dict
|
||||
:param exts: extensions given to :py:func:`waflib.Configure.find_program`
|
||||
:type exts: list
|
||||
"""
|
||||
|
||||
try:
|
||||
app = self.find_program(filename, path_list=path_list, var=var, environ=environ, exts=exts)
|
||||
except Exception:
|
||||
self.find_program('perl', var='PERL')
|
||||
app = self.find_file(filename, os.environ['PATH'].split(os.pathsep))
|
||||
if not app:
|
||||
raise
|
||||
if var:
|
||||
self.env[var] = Utils.to_list(self.env['PERL']) + [app]
|
||||
self.msg('Checking for %r' % filename, app)
|
||||
|
||||
+617
@@ -0,0 +1,617 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
"""
|
||||
Classes and functions required for waf commands
|
||||
"""
|
||||
|
||||
import os, imp, sys
|
||||
from waflib import Utils, Errors, Logs
|
||||
import waflib.Node
|
||||
|
||||
# the following 3 constants are updated on each new release (do not touch)
|
||||
HEXVERSION=0x1070b00
|
||||
"""Constant updated on new releases"""
|
||||
|
||||
WAFVERSION="1.7.11"
|
||||
"""Constant updated on new releases"""
|
||||
|
||||
WAFREVISION="50f631bc5e00bdda966c68094229b99be9a21084"
|
||||
"""Constant updated on new releases"""
|
||||
|
||||
ABI = 98
|
||||
"""Version of the build data cache file format (used in :py:const:`waflib.Context.DBFILE`)"""
|
||||
|
||||
DBFILE = '.wafpickle-%s-%d-%d' % (sys.platform, sys.hexversion, ABI)
|
||||
"""Name of the pickle file for storing the build data"""
|
||||
|
||||
APPNAME = 'APPNAME'
|
||||
"""Default application name (used by ``waf dist``)"""
|
||||
|
||||
VERSION = 'VERSION'
|
||||
"""Default application version (used by ``waf dist``)"""
|
||||
|
||||
TOP = 'top'
|
||||
"""The variable name for the top-level directory in wscript files"""
|
||||
|
||||
OUT = 'out'
|
||||
"""The variable name for the output directory in wscript files"""
|
||||
|
||||
WSCRIPT_FILE = 'wscript'
|
||||
"""Name of the waf script files"""
|
||||
|
||||
|
||||
launch_dir = ''
|
||||
"""Directory from which waf has been called"""
|
||||
run_dir = ''
|
||||
"""Location of the wscript file to use as the entry point"""
|
||||
top_dir = ''
|
||||
"""Location of the project directory (top), if the project was configured"""
|
||||
out_dir = ''
|
||||
"""Location of the build directory (out), if the project was configured"""
|
||||
waf_dir = ''
|
||||
"""Directory containing the waf modules"""
|
||||
|
||||
local_repo = ''
|
||||
"""Local repository containing additional Waf tools (plugins)"""
|
||||
remote_repo = 'http://waf.googlecode.com/git/'
|
||||
"""
|
||||
Remote directory containing downloadable waf tools. The missing tools can be downloaded by using::
|
||||
|
||||
$ waf configure --download
|
||||
"""
|
||||
|
||||
remote_locs = ['waflib/extras', 'waflib/Tools']
|
||||
"""
|
||||
Remote directories for use with :py:const:`waflib.Context.remote_repo`
|
||||
"""
|
||||
|
||||
g_module = None
|
||||
"""
|
||||
Module representing the main wscript file (see :py:const:`waflib.Context.run_dir`)
|
||||
"""
|
||||
|
||||
STDOUT = 1
|
||||
STDERR = -1
|
||||
BOTH = 0
|
||||
|
||||
classes = []
|
||||
"""
|
||||
List of :py:class:`waflib.Context.Context` subclasses that can be used as waf commands. The classes
|
||||
are added automatically by a metaclass.
|
||||
"""
|
||||
|
||||
|
||||
def create_context(cmd_name, *k, **kw):
|
||||
"""
|
||||
Create a new :py:class:`waflib.Context.Context` instance corresponding to the given command.
|
||||
Used in particular by :py:func:`waflib.Scripting.run_command`
|
||||
|
||||
:param cmd_name: command
|
||||
:type cmd_name: string
|
||||
:param k: arguments to give to the context class initializer
|
||||
:type k: list
|
||||
:param k: keyword arguments to give to the context class initializer
|
||||
:type k: dict
|
||||
"""
|
||||
global classes
|
||||
for x in classes:
|
||||
if x.cmd == cmd_name:
|
||||
return x(*k, **kw)
|
||||
ctx = Context(*k, **kw)
|
||||
ctx.fun = cmd_name
|
||||
return ctx
|
||||
|
||||
class store_context(type):
|
||||
"""
|
||||
Metaclass for storing the command classes into the list :py:const:`waflib.Context.classes`
|
||||
Context classes must provide an attribute 'cmd' representing the command to execute
|
||||
"""
|
||||
def __init__(cls, name, bases, dict):
|
||||
super(store_context, cls).__init__(name, bases, dict)
|
||||
name = cls.__name__
|
||||
|
||||
if name == 'ctx' or name == 'Context':
|
||||
return
|
||||
|
||||
try:
|
||||
cls.cmd
|
||||
except AttributeError:
|
||||
raise Errors.WafError('Missing command for the context class %r (cmd)' % name)
|
||||
|
||||
if not getattr(cls, 'fun', None):
|
||||
cls.fun = cls.cmd
|
||||
|
||||
global classes
|
||||
classes.insert(0, cls)
|
||||
|
||||
ctx = store_context('ctx', (object,), {})
|
||||
"""Base class for the :py:class:`waflib.Context.Context` classes"""
|
||||
|
||||
class Context(ctx):
|
||||
"""
|
||||
Default context for waf commands, and base class for new command contexts.
|
||||
|
||||
Context objects are passed to top-level functions::
|
||||
|
||||
def foo(ctx):
|
||||
print(ctx.__class__.__name__) # waflib.Context.Context
|
||||
|
||||
Subclasses must define the attribute 'cmd':
|
||||
|
||||
:param cmd: command to execute as in ``waf cmd``
|
||||
:type cmd: string
|
||||
:param fun: function name to execute when the command is called
|
||||
:type fun: string
|
||||
|
||||
.. inheritance-diagram:: waflib.Context.Context waflib.Build.BuildContext waflib.Build.InstallContext waflib.Build.UninstallContext waflib.Build.StepContext waflib.Build.ListContext waflib.Configure.ConfigurationContext waflib.Scripting.Dist waflib.Scripting.DistCheck waflib.Build.CleanContext
|
||||
|
||||
"""
|
||||
|
||||
errors = Errors
|
||||
"""
|
||||
Shortcut to :py:mod:`waflib.Errors` provided for convenience
|
||||
"""
|
||||
|
||||
tools = {}
|
||||
"""
|
||||
A cache for modules (wscript files) read by :py:meth:`Context.Context.load`
|
||||
"""
|
||||
|
||||
def __init__(self, **kw):
|
||||
try:
|
||||
rd = kw['run_dir']
|
||||
except KeyError:
|
||||
global run_dir
|
||||
rd = run_dir
|
||||
|
||||
# binds the context to the nodes in use to avoid a context singleton
|
||||
class node_class(waflib.Node.Node):
|
||||
pass
|
||||
self.node_class = node_class
|
||||
self.node_class.__module__ = "waflib.Node"
|
||||
self.node_class.__name__ = "Nod3"
|
||||
self.node_class.ctx = self
|
||||
|
||||
self.root = self.node_class('', None)
|
||||
self.cur_script = None
|
||||
self.path = self.root.find_dir(rd)
|
||||
|
||||
self.stack_path = []
|
||||
self.exec_dict = {'ctx':self, 'conf':self, 'bld':self, 'opt':self}
|
||||
self.logger = None
|
||||
|
||||
def __hash__(self):
|
||||
"""
|
||||
Return a hash value for storing context objects in dicts or sets. The value is not persistent.
|
||||
|
||||
:return: hash value
|
||||
:rtype: int
|
||||
"""
|
||||
return id(self)
|
||||
|
||||
def load(self, tool_list, *k, **kw):
|
||||
"""
|
||||
Load a Waf tool as a module, and try calling the function named :py:const:`waflib.Context.Context.fun` from it.
|
||||
A ``tooldir`` value may be provided as a list of module paths.
|
||||
|
||||
:type tool_list: list of string or space-separated string
|
||||
:param tool_list: list of Waf tools to use
|
||||
"""
|
||||
tools = Utils.to_list(tool_list)
|
||||
path = Utils.to_list(kw.get('tooldir', ''))
|
||||
|
||||
for t in tools:
|
||||
module = load_tool(t, path)
|
||||
fun = getattr(module, kw.get('name', self.fun), None)
|
||||
if fun:
|
||||
fun(self)
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
Execute the command. Redefine this method in subclasses.
|
||||
"""
|
||||
global g_module
|
||||
self.recurse([os.path.dirname(g_module.root_path)])
|
||||
|
||||
def pre_recurse(self, node):
|
||||
"""
|
||||
Method executed immediately before a folder is read by :py:meth:`waflib.Context.Context.recurse`. The node given is set
|
||||
as an attribute ``self.cur_script``, and as the current path ``self.path``
|
||||
|
||||
:param node: script
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
self.stack_path.append(self.cur_script)
|
||||
|
||||
self.cur_script = node
|
||||
self.path = node.parent
|
||||
|
||||
def post_recurse(self, node):
|
||||
"""
|
||||
Restore ``self.cur_script`` and ``self.path`` right after :py:meth:`waflib.Context.Context.recurse` terminates.
|
||||
|
||||
:param node: script
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
self.cur_script = self.stack_path.pop()
|
||||
if self.cur_script:
|
||||
self.path = self.cur_script.parent
|
||||
|
||||
def recurse(self, dirs, name=None, mandatory=True, once=True):
|
||||
"""
|
||||
Run user code from the supplied list of directories.
|
||||
The directories can be either absolute, or relative to the directory
|
||||
of the wscript file. The methods :py:meth:`waflib.Context.Context.pre_recurse` and :py:meth:`waflib.Context.Context.post_recurse`
|
||||
are called immediately before and after a script has been executed.
|
||||
|
||||
:param dirs: List of directories to visit
|
||||
:type dirs: list of string or space-separated string
|
||||
:param name: Name of function to invoke from the wscript
|
||||
:type name: string
|
||||
:param mandatory: whether sub wscript files are required to exist
|
||||
:type mandatory: bool
|
||||
:param once: read the script file once for a particular context
|
||||
:type once: bool
|
||||
"""
|
||||
try:
|
||||
cache = self.recurse_cache
|
||||
except AttributeError:
|
||||
cache = self.recurse_cache = {}
|
||||
|
||||
for d in Utils.to_list(dirs):
|
||||
|
||||
if not os.path.isabs(d):
|
||||
# absolute paths only
|
||||
d = os.path.join(self.path.abspath(), d)
|
||||
|
||||
WSCRIPT = os.path.join(d, WSCRIPT_FILE)
|
||||
WSCRIPT_FUN = WSCRIPT + '_' + (name or self.fun)
|
||||
|
||||
node = self.root.find_node(WSCRIPT_FUN)
|
||||
if node and (not once or node not in cache):
|
||||
cache[node] = True
|
||||
self.pre_recurse(node)
|
||||
try:
|
||||
function_code = node.read('rU')
|
||||
exec(compile(function_code, node.abspath(), 'exec'), self.exec_dict)
|
||||
finally:
|
||||
self.post_recurse(node)
|
||||
elif not node:
|
||||
node = self.root.find_node(WSCRIPT)
|
||||
tup = (node, name or self.fun)
|
||||
if node and (not once or tup not in cache):
|
||||
cache[tup] = True
|
||||
self.pre_recurse(node)
|
||||
try:
|
||||
wscript_module = load_module(node.abspath())
|
||||
user_function = getattr(wscript_module, (name or self.fun), None)
|
||||
if not user_function:
|
||||
if not mandatory:
|
||||
continue
|
||||
raise Errors.WafError('No function %s defined in %s' % (name or self.fun, node.abspath()))
|
||||
user_function(self)
|
||||
finally:
|
||||
self.post_recurse(node)
|
||||
elif not node:
|
||||
if not mandatory:
|
||||
continue
|
||||
raise Errors.WafError('No wscript file in directory %s' % d)
|
||||
|
||||
def exec_command(self, cmd, **kw):
|
||||
"""
|
||||
Execute a command and return the exit status. If the context has the attribute 'log',
|
||||
capture and log the process stderr/stdout for logging purposes::
|
||||
|
||||
def run(tsk):
|
||||
ret = tsk.generator.bld.exec_command('touch foo.txt')
|
||||
return ret
|
||||
|
||||
This method captures the standard/error outputs (Issue 1101), but it does not return the values
|
||||
unlike :py:meth:`waflib.Context.Context.cmd_and_log`
|
||||
|
||||
:param cmd: command argument for subprocess.Popen
|
||||
:param kw: keyword arguments for subprocess.Popen
|
||||
"""
|
||||
subprocess = Utils.subprocess
|
||||
kw['shell'] = isinstance(cmd, str)
|
||||
Logs.debug('runner: %r' % cmd)
|
||||
Logs.debug('runner_env: kw=%s' % kw)
|
||||
|
||||
if self.logger:
|
||||
self.logger.info(cmd)
|
||||
|
||||
if 'stdout' not in kw:
|
||||
kw['stdout'] = subprocess.PIPE
|
||||
if 'stderr' not in kw:
|
||||
kw['stderr'] = subprocess.PIPE
|
||||
|
||||
try:
|
||||
if kw['stdout'] or kw['stderr']:
|
||||
p = subprocess.Popen(cmd, **kw)
|
||||
(out, err) = p.communicate()
|
||||
ret = p.returncode
|
||||
else:
|
||||
out, err = (None, None)
|
||||
ret = subprocess.Popen(cmd, **kw).wait()
|
||||
except Exception as e:
|
||||
raise Errors.WafError('Execution failure: %s' % str(e), ex=e)
|
||||
|
||||
if out:
|
||||
if not isinstance(out, str):
|
||||
out = out.decode(sys.stdout.encoding or 'iso8859-1')
|
||||
if self.logger:
|
||||
self.logger.debug('out: %s' % out)
|
||||
else:
|
||||
sys.stdout.write(out)
|
||||
if err:
|
||||
if not isinstance(err, str):
|
||||
err = err.decode(sys.stdout.encoding or 'iso8859-1')
|
||||
if self.logger:
|
||||
self.logger.error('err: %s' % err)
|
||||
else:
|
||||
sys.stderr.write(err)
|
||||
|
||||
return ret
|
||||
|
||||
def cmd_and_log(self, cmd, **kw):
|
||||
"""
|
||||
Execute a command and return stdout if the execution is successful.
|
||||
An exception is thrown when the exit status is non-0. In that case, both stderr and stdout
|
||||
will be bound to the WafError object::
|
||||
|
||||
def configure(conf):
|
||||
out = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.STDOUT, quiet=waflib.Context.BOTH)
|
||||
(out, err) = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.BOTH)
|
||||
try:
|
||||
conf.cmd_and_log(['which', 'someapp'], output=waflib.Context.BOTH)
|
||||
except Exception as e:
|
||||
print(e.stdout, e.stderr)
|
||||
|
||||
:param cmd: args for subprocess.Popen
|
||||
:param kw: keyword arguments for subprocess.Popen
|
||||
"""
|
||||
subprocess = Utils.subprocess
|
||||
kw['shell'] = isinstance(cmd, str)
|
||||
Logs.debug('runner: %r' % cmd)
|
||||
|
||||
if 'quiet' in kw:
|
||||
quiet = kw['quiet']
|
||||
del kw['quiet']
|
||||
else:
|
||||
quiet = None
|
||||
|
||||
if 'output' in kw:
|
||||
to_ret = kw['output']
|
||||
del kw['output']
|
||||
else:
|
||||
to_ret = STDOUT
|
||||
|
||||
kw['stdout'] = kw['stderr'] = subprocess.PIPE
|
||||
if quiet is None:
|
||||
self.to_log(cmd)
|
||||
try:
|
||||
p = subprocess.Popen(cmd, **kw)
|
||||
(out, err) = p.communicate()
|
||||
except Exception as e:
|
||||
raise Errors.WafError('Execution failure: %s' % str(e), ex=e)
|
||||
|
||||
if not isinstance(out, str):
|
||||
out = out.decode(sys.stdout.encoding or 'iso8859-1')
|
||||
if not isinstance(err, str):
|
||||
err = err.decode(sys.stdout.encoding or 'iso8859-1')
|
||||
|
||||
if out and quiet != STDOUT and quiet != BOTH:
|
||||
self.to_log('out: %s' % out)
|
||||
if err and quiet != STDERR and quiet != BOTH:
|
||||
self.to_log('err: %s' % err)
|
||||
|
||||
if p.returncode:
|
||||
e = Errors.WafError('Command %r returned %r' % (cmd, p.returncode))
|
||||
e.returncode = p.returncode
|
||||
e.stderr = err
|
||||
e.stdout = out
|
||||
raise e
|
||||
|
||||
if to_ret == BOTH:
|
||||
return (out, err)
|
||||
elif to_ret == STDERR:
|
||||
return err
|
||||
return out
|
||||
|
||||
def fatal(self, msg, ex=None):
|
||||
"""
|
||||
Raise a configuration error to interrupt the execution immediately::
|
||||
|
||||
def configure(conf):
|
||||
conf.fatal('a requirement is missing')
|
||||
|
||||
:param msg: message to display
|
||||
:type msg: string
|
||||
:param ex: optional exception object
|
||||
:type ex: exception
|
||||
"""
|
||||
if self.logger:
|
||||
self.logger.info('from %s: %s' % (self.path.abspath(), msg))
|
||||
try:
|
||||
msg = '%s\n(complete log in %s)' % (msg, self.logger.handlers[0].baseFilename)
|
||||
except Exception:
|
||||
pass
|
||||
raise self.errors.ConfigurationError(msg, ex=ex)
|
||||
|
||||
def to_log(self, msg):
|
||||
"""
|
||||
Log some information to the logger (if present), or to stderr. If the message is empty,
|
||||
it is not printed::
|
||||
|
||||
def build(bld):
|
||||
bld.to_log('starting the build')
|
||||
|
||||
When in doubt, override this method, or provide a logger on the context class.
|
||||
|
||||
:param msg: message
|
||||
:type msg: string
|
||||
"""
|
||||
if not msg:
|
||||
return
|
||||
if self.logger:
|
||||
self.logger.info(msg)
|
||||
else:
|
||||
sys.stderr.write(str(msg))
|
||||
sys.stderr.flush()
|
||||
|
||||
|
||||
def msg(self, msg, result, color=None):
|
||||
"""
|
||||
Print a configuration message of the form ``msg: result``.
|
||||
The second part of the message will be in colors. The output
|
||||
can be disabled easly by setting ``in_msg`` to a positive value::
|
||||
|
||||
def configure(conf):
|
||||
self.in_msg = 1
|
||||
conf.msg('Checking for library foo', 'ok')
|
||||
# no output
|
||||
|
||||
:param msg: message to display to the user
|
||||
:type msg: string
|
||||
:param result: result to display
|
||||
:type result: string or boolean
|
||||
:param color: color to use, see :py:const:`waflib.Logs.colors_lst`
|
||||
:type color: string
|
||||
"""
|
||||
self.start_msg(msg)
|
||||
|
||||
if not isinstance(color, str):
|
||||
color = result and 'GREEN' or 'YELLOW'
|
||||
|
||||
self.end_msg(result, color)
|
||||
|
||||
def start_msg(self, msg):
|
||||
"""
|
||||
Print the beginning of a 'Checking for xxx' message. See :py:meth:`waflib.Context.Context.msg`
|
||||
"""
|
||||
try:
|
||||
if self.in_msg:
|
||||
self.in_msg += 1
|
||||
return
|
||||
except AttributeError:
|
||||
self.in_msg = 0
|
||||
self.in_msg += 1
|
||||
|
||||
try:
|
||||
self.line_just = max(self.line_just, len(msg))
|
||||
except AttributeError:
|
||||
self.line_just = max(40, len(msg))
|
||||
for x in (self.line_just * '-', msg):
|
||||
self.to_log(x)
|
||||
Logs.pprint('NORMAL', "%s :" % msg.ljust(self.line_just), sep='')
|
||||
|
||||
def end_msg(self, result, color=None):
|
||||
"""Print the end of a 'Checking for' message. See :py:meth:`waflib.Context.Context.msg`"""
|
||||
self.in_msg -= 1
|
||||
if self.in_msg:
|
||||
return
|
||||
|
||||
defcolor = 'GREEN'
|
||||
if result == True:
|
||||
msg = 'ok'
|
||||
elif result == False:
|
||||
msg = 'not found'
|
||||
defcolor = 'YELLOW'
|
||||
else:
|
||||
msg = str(result)
|
||||
|
||||
self.to_log(msg)
|
||||
Logs.pprint(color or defcolor, msg)
|
||||
|
||||
|
||||
def load_special_tools(self, var, ban=[]):
|
||||
global waf_dir
|
||||
lst = self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var)
|
||||
for x in lst:
|
||||
if not x.name in ban:
|
||||
load_tool(x.name.replace('.py', ''))
|
||||
|
||||
cache_modules = {}
|
||||
"""
|
||||
Dictionary holding already loaded modules, keyed by their absolute path.
|
||||
The modules are added automatically by :py:func:`waflib.Context.load_module`
|
||||
"""
|
||||
|
||||
def load_module(path):
|
||||
"""
|
||||
Load a source file as a python module.
|
||||
|
||||
:param path: file path
|
||||
:type path: string
|
||||
:return: Loaded Python module
|
||||
:rtype: module
|
||||
"""
|
||||
try:
|
||||
return cache_modules[path]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
module = imp.new_module(WSCRIPT_FILE)
|
||||
try:
|
||||
code = Utils.readf(path, m='rU')
|
||||
except (IOError, OSError):
|
||||
raise Errors.WafError('Could not read the file %r' % path)
|
||||
|
||||
module_dir = os.path.dirname(path)
|
||||
sys.path.insert(0, module_dir)
|
||||
|
||||
exec(compile(code, path, 'exec'), module.__dict__)
|
||||
sys.path.remove(module_dir)
|
||||
|
||||
cache_modules[path] = module
|
||||
|
||||
return module
|
||||
|
||||
def load_tool(tool, tooldir=None):
|
||||
"""
|
||||
Import a Waf tool (python module), and store it in the dict :py:const:`waflib.Context.Context.tools`
|
||||
|
||||
:type tool: string
|
||||
:param tool: Name of the tool
|
||||
:type tooldir: list
|
||||
:param tooldir: List of directories to search for the tool module
|
||||
"""
|
||||
if tool == 'java':
|
||||
tool = 'javaw' # jython
|
||||
elif tool == 'compiler_cc':
|
||||
tool = 'compiler_c' # TODO remove in waf 1.8
|
||||
else:
|
||||
tool = tool.replace('++', 'xx')
|
||||
|
||||
if tooldir:
|
||||
assert isinstance(tooldir, list)
|
||||
sys.path = tooldir + sys.path
|
||||
try:
|
||||
__import__(tool)
|
||||
ret = sys.modules[tool]
|
||||
Context.tools[tool] = ret
|
||||
return ret
|
||||
finally:
|
||||
for d in tooldir:
|
||||
sys.path.remove(d)
|
||||
else:
|
||||
global waf_dir
|
||||
try:
|
||||
os.stat(os.path.join(waf_dir, 'waflib', 'extras', tool + '.py'))
|
||||
except OSError:
|
||||
try:
|
||||
os.stat(os.path.join(waf_dir, 'waflib', 'Tools', tool + '.py'))
|
||||
except OSError:
|
||||
d = tool # user has messed with sys.path
|
||||
else:
|
||||
d = 'waflib.Tools.%s' % tool
|
||||
else:
|
||||
d = 'waflib.extras.%s' % tool
|
||||
|
||||
__import__(d)
|
||||
ret = sys.modules[d]
|
||||
Context.tools[tool] = ret
|
||||
return ret
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
"""
|
||||
Exceptions used in the Waf code
|
||||
"""
|
||||
|
||||
import traceback, sys
|
||||
|
||||
class WafError(Exception):
|
||||
"""Base class for all Waf errors"""
|
||||
def __init__(self, msg='', ex=None):
|
||||
"""
|
||||
:param msg: error message
|
||||
:type msg: string
|
||||
:param ex: exception causing this error (optional)
|
||||
:type ex: exception
|
||||
"""
|
||||
self.msg = msg
|
||||
assert not isinstance(msg, Exception)
|
||||
|
||||
self.stack = []
|
||||
if ex:
|
||||
if not msg:
|
||||
self.msg = str(ex)
|
||||
if isinstance(ex, WafError):
|
||||
self.stack = ex.stack
|
||||
else:
|
||||
self.stack = traceback.extract_tb(sys.exc_info()[2])
|
||||
self.stack += traceback.extract_stack()[:-1]
|
||||
self.verbose_msg = ''.join(traceback.format_list(self.stack))
|
||||
|
||||
def __str__(self):
|
||||
return str(self.msg)
|
||||
|
||||
class BuildError(WafError):
|
||||
"""
|
||||
Errors raised during the build and install phases
|
||||
"""
|
||||
def __init__(self, error_tasks=[]):
|
||||
"""
|
||||
:param error_tasks: tasks that could not complete normally
|
||||
:type error_tasks: list of task objects
|
||||
"""
|
||||
self.tasks = error_tasks
|
||||
WafError.__init__(self, self.format_error())
|
||||
|
||||
def format_error(self):
|
||||
"""format the error messages from the tasks that failed"""
|
||||
lst = ['Build failed']
|
||||
for tsk in self.tasks:
|
||||
txt = tsk.format_error()
|
||||
if txt: lst.append(txt)
|
||||
return '\n'.join(lst)
|
||||
|
||||
class ConfigurationError(WafError):
|
||||
"""
|
||||
Configuration exception raised in particular by :py:meth:`waflib.Context.Context.fatal`
|
||||
"""
|
||||
pass
|
||||
|
||||
class TaskRescan(WafError):
|
||||
"""task-specific exception type, trigger a signature recomputation"""
|
||||
pass
|
||||
|
||||
class TaskNotReady(WafError):
|
||||
"""task-specific exception type, raised when the task signature cannot be computed"""
|
||||
pass
|
||||
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
logging, colors, terminal width and pretty-print
|
||||
"""
|
||||
|
||||
import os, re, traceback, sys
|
||||
|
||||
try:
|
||||
import threading
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
wlock = threading.Lock()
|
||||
|
||||
class sync_stream(object):
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
self.encoding = self.stream.encoding
|
||||
|
||||
def write(self, txt):
|
||||
try:
|
||||
wlock.acquire()
|
||||
self.stream.write(txt)
|
||||
self.stream.flush()
|
||||
finally:
|
||||
wlock.release()
|
||||
|
||||
def fileno(self):
|
||||
return self.stream.fileno()
|
||||
|
||||
def flush(self):
|
||||
self.stream.flush()
|
||||
|
||||
def isatty(self):
|
||||
return self.stream.isatty()
|
||||
|
||||
_nocolor = os.environ.get('NOCOLOR', 'no') not in ('no', '0', 'false')
|
||||
try:
|
||||
if not _nocolor:
|
||||
import waflib.ansiterm
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
if not os.environ.get('NOSYNC', False):
|
||||
if id(sys.stdout) == id(sys.__stdout__):
|
||||
sys.stdout = sync_stream(sys.stdout)
|
||||
sys.stderr = sync_stream(sys.stderr)
|
||||
|
||||
import logging # import other modules only after
|
||||
|
||||
LOG_FORMAT = "%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s"
|
||||
HOUR_FORMAT = "%H:%M:%S"
|
||||
|
||||
zones = ''
|
||||
verbose = 0
|
||||
|
||||
colors_lst = {
|
||||
'USE' : True,
|
||||
'BOLD' :'\x1b[01;1m',
|
||||
'RED' :'\x1b[01;31m',
|
||||
'GREEN' :'\x1b[32m',
|
||||
'YELLOW':'\x1b[33m',
|
||||
'PINK' :'\x1b[35m',
|
||||
'BLUE' :'\x1b[01;34m',
|
||||
'CYAN' :'\x1b[36m',
|
||||
'NORMAL':'\x1b[0m',
|
||||
'cursor_on' :'\x1b[?25h',
|
||||
'cursor_off' :'\x1b[?25l',
|
||||
}
|
||||
|
||||
got_tty = not os.environ.get('TERM', 'dumb') in ['dumb', 'emacs']
|
||||
if got_tty:
|
||||
try:
|
||||
got_tty = sys.stderr.isatty() and sys.stdout.isatty()
|
||||
except AttributeError:
|
||||
got_tty = False
|
||||
|
||||
if (not got_tty and os.environ.get('TERM', 'dumb') != 'msys') or _nocolor:
|
||||
colors_lst['USE'] = False
|
||||
|
||||
def get_term_cols():
|
||||
return 80
|
||||
|
||||
# If console packages are available, replace the dummy function with a real
|
||||
# implementation
|
||||
try:
|
||||
import struct, fcntl, termios
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if got_tty:
|
||||
def get_term_cols_real():
|
||||
"""
|
||||
Private use only.
|
||||
"""
|
||||
|
||||
dummy_lines, cols = struct.unpack("HHHH", \
|
||||
fcntl.ioctl(sys.stderr.fileno(),termios.TIOCGWINSZ , \
|
||||
struct.pack("HHHH", 0, 0, 0, 0)))[:2]
|
||||
return cols
|
||||
# try the function once to see if it really works
|
||||
try:
|
||||
get_term_cols_real()
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
get_term_cols = get_term_cols_real
|
||||
|
||||
get_term_cols.__doc__ = """
|
||||
Get the console width in characters.
|
||||
|
||||
:return: the number of characters per line
|
||||
:rtype: int
|
||||
"""
|
||||
|
||||
def get_color(cl):
|
||||
if not colors_lst['USE']: return ''
|
||||
return colors_lst.get(cl, '')
|
||||
|
||||
class color_dict(object):
|
||||
"""attribute-based color access, eg: colors.PINK"""
|
||||
def __getattr__(self, a):
|
||||
return get_color(a)
|
||||
def __call__(self, a):
|
||||
return get_color(a)
|
||||
|
||||
colors = color_dict()
|
||||
|
||||
re_log = re.compile(r'(\w+): (.*)', re.M)
|
||||
class log_filter(logging.Filter):
|
||||
"""
|
||||
The waf logs are of the form 'name: message', and can be filtered by 'waf --zones=name'.
|
||||
For example, the following::
|
||||
|
||||
from waflib import Logs
|
||||
Logs.debug('test: here is a message')
|
||||
|
||||
Will be displayed only when executing::
|
||||
|
||||
$ waf --zones=test
|
||||
"""
|
||||
def __init__(self, name=None):
|
||||
pass
|
||||
|
||||
def filter(self, rec):
|
||||
"""
|
||||
filter a record, adding the colors automatically
|
||||
|
||||
* error: red
|
||||
* warning: yellow
|
||||
|
||||
:param rec: message to record
|
||||
"""
|
||||
|
||||
rec.c1 = colors.PINK
|
||||
rec.c2 = colors.NORMAL
|
||||
rec.zone = rec.module
|
||||
if rec.levelno >= logging.INFO:
|
||||
if rec.levelno >= logging.ERROR:
|
||||
rec.c1 = colors.RED
|
||||
elif rec.levelno >= logging.WARNING:
|
||||
rec.c1 = colors.YELLOW
|
||||
else:
|
||||
rec.c1 = colors.GREEN
|
||||
return True
|
||||
|
||||
m = re_log.match(rec.msg)
|
||||
if m:
|
||||
rec.zone = m.group(1)
|
||||
rec.msg = m.group(2)
|
||||
|
||||
if zones:
|
||||
return getattr(rec, 'zone', '') in zones or '*' in zones
|
||||
elif not verbose > 2:
|
||||
return False
|
||||
return True
|
||||
|
||||
class formatter(logging.Formatter):
|
||||
"""Simple log formatter which handles colors"""
|
||||
def __init__(self):
|
||||
logging.Formatter.__init__(self, LOG_FORMAT, HOUR_FORMAT)
|
||||
|
||||
def format(self, rec):
|
||||
"""Messages in warning, error or info mode are displayed in color by default"""
|
||||
if rec.levelno >= logging.WARNING or rec.levelno == logging.INFO:
|
||||
try:
|
||||
msg = rec.msg.decode('utf-8')
|
||||
except Exception:
|
||||
msg = rec.msg
|
||||
return '%s%s%s' % (rec.c1, msg, rec.c2)
|
||||
return logging.Formatter.format(self, rec)
|
||||
|
||||
log = None
|
||||
"""global logger for Logs.debug, Logs.error, etc"""
|
||||
|
||||
def debug(*k, **kw):
|
||||
"""
|
||||
Wrap logging.debug, the output is filtered for performance reasons
|
||||
"""
|
||||
if verbose:
|
||||
k = list(k)
|
||||
k[0] = k[0].replace('\n', ' ')
|
||||
global log
|
||||
log.debug(*k, **kw)
|
||||
|
||||
def error(*k, **kw):
|
||||
"""
|
||||
Wrap logging.errors, display the origin of the message when '-vv' is set
|
||||
"""
|
||||
global log
|
||||
log.error(*k, **kw)
|
||||
if verbose > 2:
|
||||
st = traceback.extract_stack()
|
||||
if st:
|
||||
st = st[:-1]
|
||||
buf = []
|
||||
for filename, lineno, name, line in st:
|
||||
buf.append(' File "%s", line %d, in %s' % (filename, lineno, name))
|
||||
if line:
|
||||
buf.append(' %s' % line.strip())
|
||||
if buf: log.error("\n".join(buf))
|
||||
|
||||
def warn(*k, **kw):
|
||||
"""
|
||||
Wrap logging.warn
|
||||
"""
|
||||
global log
|
||||
log.warn(*k, **kw)
|
||||
|
||||
def info(*k, **kw):
|
||||
"""
|
||||
Wrap logging.info
|
||||
"""
|
||||
global log
|
||||
log.info(*k, **kw)
|
||||
|
||||
def init_log():
|
||||
"""
|
||||
Initialize the loggers globally
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger('waflib')
|
||||
log.handlers = []
|
||||
log.filters = []
|
||||
hdlr = logging.StreamHandler()
|
||||
hdlr.setFormatter(formatter())
|
||||
log.addHandler(hdlr)
|
||||
log.addFilter(log_filter())
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
def make_logger(path, name):
|
||||
"""
|
||||
Create a simple logger, which is often used to redirect the context command output::
|
||||
|
||||
from waflib import Logs
|
||||
bld.logger = Logs.make_logger('test.log', 'build')
|
||||
bld.check(header_name='sadlib.h', features='cxx cprogram', mandatory=False)
|
||||
bld.logger = None
|
||||
|
||||
:param path: file name to write the log output to
|
||||
:type path: string
|
||||
:param name: logger name (loggers are reused)
|
||||
:type name: string
|
||||
"""
|
||||
logger = logging.getLogger(name)
|
||||
hdlr = logging.FileHandler(path, 'w')
|
||||
formatter = logging.Formatter('%(message)s')
|
||||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
return logger
|
||||
|
||||
def make_mem_logger(name, to_log, size=10000):
|
||||
"""
|
||||
Create a memory logger to avoid writing concurrently to the main logger
|
||||
"""
|
||||
from logging.handlers import MemoryHandler
|
||||
logger = logging.getLogger(name)
|
||||
hdlr = MemoryHandler(size, target=to_log)
|
||||
formatter = logging.Formatter('%(message)s')
|
||||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
logger.memhandler = hdlr
|
||||
logger.setLevel(logging.DEBUG)
|
||||
return logger
|
||||
|
||||
def pprint(col, str, label='', sep='\n'):
|
||||
"""
|
||||
Print messages in color immediately on stderr::
|
||||
|
||||
from waflib import Logs
|
||||
Logs.pprint('RED', 'Something bad just happened')
|
||||
|
||||
:param col: color name to use in :py:const:`Logs.colors_lst`
|
||||
:type col: string
|
||||
:param str: message to display
|
||||
:type str: string or a value that can be printed by %s
|
||||
:param label: a message to add after the colored output
|
||||
:type label: string
|
||||
:param sep: a string to append at the end (line separator)
|
||||
:type sep: string
|
||||
"""
|
||||
sys.stderr.write("%s%s%s %s%s" % (colors(col), str, colors.NORMAL, label, sep))
|
||||
|
||||
+812
@@ -0,0 +1,812 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
Node: filesystem structure, contains lists of nodes
|
||||
|
||||
#. Each file/folder is represented by exactly one node.
|
||||
|
||||
#. Some potential class properties are stored on :py:class:`waflib.Build.BuildContext` : nodes to depend on, etc.
|
||||
Unused class members can increase the `.wafpickle` file size sensibly.
|
||||
|
||||
#. Node objects should never be created directly, use
|
||||
the methods :py:func:`Node.make_node` or :py:func:`Node.find_node`
|
||||
|
||||
#. The methods :py:func:`Node.find_resource`, :py:func:`Node.find_dir` :py:func:`Node.find_or_declare` should be
|
||||
used when a build context is present
|
||||
|
||||
#. Each instance of :py:class:`waflib.Context.Context` has a unique :py:class:`Node` subclass.
|
||||
(:py:class:`waflib.Node.Nod3`, see the :py:class:`waflib.Context.Context` initializer). A reference to the context owning a node is held as self.ctx
|
||||
"""
|
||||
|
||||
import os, re, sys, shutil
|
||||
from waflib import Utils, Errors
|
||||
|
||||
exclude_regs = '''
|
||||
**/*~
|
||||
**/#*#
|
||||
**/.#*
|
||||
**/%*%
|
||||
**/._*
|
||||
**/CVS
|
||||
**/CVS/**
|
||||
**/.cvsignore
|
||||
**/SCCS
|
||||
**/SCCS/**
|
||||
**/vssver.scc
|
||||
**/.svn
|
||||
**/.svn/**
|
||||
**/BitKeeper
|
||||
**/.git
|
||||
**/.git/**
|
||||
**/.gitignore
|
||||
**/.bzr
|
||||
**/.bzrignore
|
||||
**/.bzr/**
|
||||
**/.hg
|
||||
**/.hg/**
|
||||
**/_MTN
|
||||
**/_MTN/**
|
||||
**/.arch-ids
|
||||
**/{arch}
|
||||
**/_darcs
|
||||
**/_darcs/**
|
||||
**/.intlcache
|
||||
**/.DS_Store'''
|
||||
"""
|
||||
Ant patterns for files and folders to exclude while doing the
|
||||
recursive traversal in :py:meth:`waflib.Node.Node.ant_glob`
|
||||
"""
|
||||
|
||||
def split_path(path):
|
||||
"""
|
||||
Split a path by os.sep (This is not os.path.split)
|
||||
|
||||
:param path: path to split
|
||||
:type path: string
|
||||
:rtype: list of string
|
||||
:return: the path, split
|
||||
"""
|
||||
return path.split('/')
|
||||
|
||||
def split_path_cygwin(path):
|
||||
if path.startswith('//'):
|
||||
ret = path.split('/')[2:]
|
||||
ret[0] = '/' + ret[0]
|
||||
return ret
|
||||
return path.split('/')
|
||||
|
||||
re_sp = re.compile('[/\\\\]')
|
||||
def split_path_win32(path):
|
||||
if path.startswith('\\\\'):
|
||||
ret = re.split(re_sp, path)[2:]
|
||||
ret[0] = '\\' + ret[0]
|
||||
return ret
|
||||
return re.split(re_sp, path)
|
||||
|
||||
if sys.platform == 'cygwin':
|
||||
split_path = split_path_cygwin
|
||||
elif Utils.is_win32:
|
||||
split_path = split_path_win32
|
||||
|
||||
class Node(object):
|
||||
"""
|
||||
This class is organized in two parts
|
||||
|
||||
* The basic methods meant for filesystem access (compute paths, create folders, etc)
|
||||
* The methods bound to a :py:class:`waflib.Build.BuildContext` (require ``bld.srcnode`` and ``bld.bldnode``)
|
||||
|
||||
The Node objects are not thread safe in any way.
|
||||
"""
|
||||
|
||||
__slots__ = ('name', 'sig', 'children', 'parent', 'cache_abspath', 'cache_isdir', 'cache_sig')
|
||||
def __init__(self, name, parent):
|
||||
self.name = name
|
||||
self.parent = parent
|
||||
|
||||
if parent:
|
||||
if name in parent.children:
|
||||
raise Errors.WafError('node %s exists in the parent files %r already' % (name, parent))
|
||||
parent.children[name] = self
|
||||
|
||||
def __setstate__(self, data):
|
||||
"Deserializes from data"
|
||||
self.name = data[0]
|
||||
self.parent = data[1]
|
||||
if data[2] is not None:
|
||||
self.children = data[2]
|
||||
if data[3] is not None:
|
||||
self.sig = data[3]
|
||||
|
||||
def __getstate__(self):
|
||||
"Serialize the node info"
|
||||
return (self.name, self.parent, getattr(self, 'children', None), getattr(self, 'sig', None))
|
||||
|
||||
def __str__(self):
|
||||
"String representation (name), for debugging purposes"
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
"String representation (abspath), for debugging purposes"
|
||||
return self.abspath()
|
||||
|
||||
def __hash__(self):
|
||||
"Node hash, used for storage in dicts. This hash is not persistent."
|
||||
return id(self)
|
||||
|
||||
def __eq__(self, node):
|
||||
"Node comparison, based on the IDs"
|
||||
return id(self) == id(node)
|
||||
|
||||
def __copy__(self):
|
||||
"Implemented to prevent nodes from being copied (raises an exception)"
|
||||
raise Errors.WafError('nodes are not supposed to be copied')
|
||||
|
||||
def read(self, flags='r', encoding='ISO8859-1'):
|
||||
"""
|
||||
Return the contents of the file represented by this node::
|
||||
|
||||
def build(bld):
|
||||
bld.path.find_node('wscript').read()
|
||||
|
||||
:type fname: string
|
||||
:param fname: Path to file
|
||||
:type m: string
|
||||
:param m: Open mode
|
||||
:rtype: string
|
||||
:return: File contents
|
||||
"""
|
||||
return Utils.readf(self.abspath(), flags, encoding)
|
||||
|
||||
def write(self, data, flags='w', encoding='ISO8859-1'):
|
||||
"""
|
||||
Write some text to the physical file represented by this node::
|
||||
|
||||
def build(bld):
|
||||
bld.path.make_node('foo.txt').write('Hello, world!')
|
||||
|
||||
:type data: string
|
||||
:param data: data to write
|
||||
:type flags: string
|
||||
:param flags: Write mode
|
||||
"""
|
||||
Utils.writef(self.abspath(), data, flags, encoding)
|
||||
|
||||
def chmod(self, val):
|
||||
"""
|
||||
Change file/dir permissions::
|
||||
|
||||
def build(bld):
|
||||
bld.path.chmod(493) # 0755
|
||||
"""
|
||||
os.chmod(self.abspath(), val)
|
||||
|
||||
def delete(self):
|
||||
"""Delete the file/folders, and remove this node from the tree. It becomes invalid after that"""
|
||||
try:
|
||||
if hasattr(self, 'children'):
|
||||
shutil.rmtree(self.abspath())
|
||||
else:
|
||||
os.remove(self.abspath())
|
||||
except OSError:
|
||||
pass
|
||||
self.evict()
|
||||
|
||||
def evict(self):
|
||||
"""Internal - called when a node is removed"""
|
||||
del self.parent.children[self.name]
|
||||
|
||||
def suffix(self):
|
||||
"""Return the file extension"""
|
||||
k = max(0, self.name.rfind('.'))
|
||||
return self.name[k:]
|
||||
|
||||
def height(self):
|
||||
"""Depth in the folder hierarchy from the filesystem root or from all the file drives"""
|
||||
d = self
|
||||
val = -1
|
||||
while d:
|
||||
d = d.parent
|
||||
val += 1
|
||||
return val
|
||||
|
||||
def listdir(self):
|
||||
"""List the folder contents"""
|
||||
lst = Utils.listdir(self.abspath())
|
||||
lst.sort()
|
||||
return lst
|
||||
|
||||
def mkdir(self):
|
||||
"""
|
||||
Create a folder represented by this node, creating intermediate nodes as needed
|
||||
An exception will be raised only when the folder cannot possibly exist there
|
||||
"""
|
||||
if getattr(self, 'cache_isdir', None):
|
||||
return
|
||||
|
||||
try:
|
||||
self.parent.mkdir()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if self.name:
|
||||
try:
|
||||
os.makedirs(self.abspath())
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if not os.path.isdir(self.abspath()):
|
||||
raise Errors.WafError('Could not create the directory %s' % self.abspath())
|
||||
|
||||
try:
|
||||
self.children
|
||||
except AttributeError:
|
||||
self.children = {}
|
||||
|
||||
self.cache_isdir = True
|
||||
|
||||
def find_node(self, lst):
|
||||
"""
|
||||
Find a node on the file system (files or folders), create intermediate nodes as needed
|
||||
|
||||
:param lst: path
|
||||
:type lst: string or list of string
|
||||
"""
|
||||
|
||||
if isinstance(lst, str):
|
||||
lst = [x for x in split_path(lst) if x and x != '.']
|
||||
|
||||
cur = self
|
||||
for x in lst:
|
||||
if x == '..':
|
||||
cur = cur.parent or cur
|
||||
continue
|
||||
|
||||
try:
|
||||
ch = cur.children
|
||||
except AttributeError:
|
||||
cur.children = {}
|
||||
else:
|
||||
try:
|
||||
cur = cur.children[x]
|
||||
continue
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# optimistic: create the node first then look if it was correct to do so
|
||||
cur = self.__class__(x, cur)
|
||||
try:
|
||||
os.stat(cur.abspath())
|
||||
except OSError:
|
||||
cur.evict()
|
||||
return None
|
||||
|
||||
ret = cur
|
||||
|
||||
try:
|
||||
os.stat(ret.abspath())
|
||||
except OSError:
|
||||
ret.evict()
|
||||
return None
|
||||
|
||||
try:
|
||||
while not getattr(cur.parent, 'cache_isdir', None):
|
||||
cur = cur.parent
|
||||
cur.cache_isdir = True
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
def make_node(self, lst):
|
||||
"""
|
||||
Find or create a node without looking on the filesystem
|
||||
|
||||
:param lst: path
|
||||
:type lst: string or list of string
|
||||
"""
|
||||
if isinstance(lst, str):
|
||||
lst = [x for x in split_path(lst) if x and x != '.']
|
||||
|
||||
cur = self
|
||||
for x in lst:
|
||||
if x == '..':
|
||||
cur = cur.parent or cur
|
||||
continue
|
||||
|
||||
if getattr(cur, 'children', {}):
|
||||
if x in cur.children:
|
||||
cur = cur.children[x]
|
||||
continue
|
||||
else:
|
||||
cur.children = {}
|
||||
cur = self.__class__(x, cur)
|
||||
return cur
|
||||
|
||||
def search_node(self, lst):
|
||||
"""
|
||||
Search for a node without looking on the filesystem
|
||||
|
||||
:param lst: path
|
||||
:type lst: string or list of string
|
||||
"""
|
||||
if isinstance(lst, str):
|
||||
lst = [x for x in split_path(lst) if x and x != '.']
|
||||
|
||||
cur = self
|
||||
for x in lst:
|
||||
if x == '..':
|
||||
cur = cur.parent or cur
|
||||
else:
|
||||
try:
|
||||
cur = cur.children[x]
|
||||
except (AttributeError, KeyError):
|
||||
return None
|
||||
return cur
|
||||
|
||||
def path_from(self, node):
|
||||
"""
|
||||
Path of this node seen from the other::
|
||||
|
||||
def build(bld):
|
||||
n1 = bld.path.find_node('foo/bar/xyz.txt')
|
||||
n2 = bld.path.find_node('foo/stuff/')
|
||||
n1.path_from(n2) # '../bar/xyz.txt'
|
||||
|
||||
:param node: path to use as a reference
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
|
||||
c1 = self
|
||||
c2 = node
|
||||
|
||||
c1h = c1.height()
|
||||
c2h = c2.height()
|
||||
|
||||
lst = []
|
||||
up = 0
|
||||
|
||||
while c1h > c2h:
|
||||
lst.append(c1.name)
|
||||
c1 = c1.parent
|
||||
c1h -= 1
|
||||
|
||||
while c2h > c1h:
|
||||
up += 1
|
||||
c2 = c2.parent
|
||||
c2h -= 1
|
||||
|
||||
while id(c1) != id(c2):
|
||||
lst.append(c1.name)
|
||||
up += 1
|
||||
|
||||
c1 = c1.parent
|
||||
c2 = c2.parent
|
||||
|
||||
for i in range(up):
|
||||
lst.append('..')
|
||||
lst.reverse()
|
||||
return os.sep.join(lst) or '.'
|
||||
|
||||
def abspath(self):
|
||||
"""
|
||||
Absolute path. A cache is kept in the context as ``cache_node_abspath``
|
||||
"""
|
||||
try:
|
||||
return self.cache_abspath
|
||||
except AttributeError:
|
||||
pass
|
||||
# think twice before touching this (performance + complexity + correctness)
|
||||
|
||||
if os.sep == '/':
|
||||
if not self.parent:
|
||||
val = os.sep
|
||||
elif not self.parent.name:
|
||||
val = os.sep + self.name
|
||||
else:
|
||||
val = self.parent.abspath() + os.sep + self.name
|
||||
else:
|
||||
if not self.parent:
|
||||
val = ''
|
||||
elif not self.parent.name:
|
||||
val = self.name + os.sep
|
||||
else:
|
||||
val = self.parent.abspath().rstrip(os.sep) + os.sep + self.name
|
||||
|
||||
self.cache_abspath = val
|
||||
return val
|
||||
|
||||
def is_child_of(self, node):
|
||||
"""
|
||||
Does this node belong to the subtree node?::
|
||||
|
||||
def build(bld):
|
||||
node = bld.path.find_node('wscript')
|
||||
node.is_child_of(bld.path) # True
|
||||
|
||||
:param node: path to use as a reference
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
p = self
|
||||
diff = self.height() - node.height()
|
||||
while diff > 0:
|
||||
diff -= 1
|
||||
p = p.parent
|
||||
return id(p) == id(node)
|
||||
|
||||
def ant_iter(self, accept=None, maxdepth=25, pats=[], dir=False, src=True, remove=True):
|
||||
"""
|
||||
Semi-private and recursive method used by ant_glob.
|
||||
|
||||
:param accept: function used for accepting/rejecting a node, returns the patterns that can be still accepted in recursion
|
||||
:type accept: function
|
||||
:param maxdepth: maximum depth in the filesystem (25)
|
||||
:type maxdepth: int
|
||||
:param pats: list of patterns to accept and list of patterns to exclude
|
||||
:type pats: tuple
|
||||
:param dir: return folders too (False by default)
|
||||
:type dir: bool
|
||||
:param src: return files (True by default)
|
||||
:type src: bool
|
||||
:param remove: remove files/folders that do not exist (True by default)
|
||||
:type remove: bool
|
||||
"""
|
||||
dircont = self.listdir()
|
||||
dircont.sort()
|
||||
|
||||
try:
|
||||
lst = set(self.children.keys())
|
||||
except AttributeError:
|
||||
self.children = {}
|
||||
else:
|
||||
if remove:
|
||||
for x in lst - set(dircont):
|
||||
self.children[x].evict()
|
||||
|
||||
for name in dircont:
|
||||
npats = accept(name, pats)
|
||||
if npats and npats[0]:
|
||||
accepted = [] in npats[0]
|
||||
|
||||
node = self.make_node([name])
|
||||
|
||||
isdir = os.path.isdir(node.abspath())
|
||||
if accepted:
|
||||
if isdir:
|
||||
if dir:
|
||||
yield node
|
||||
else:
|
||||
if src:
|
||||
yield node
|
||||
|
||||
if getattr(node, 'cache_isdir', None) or isdir:
|
||||
node.cache_isdir = True
|
||||
if maxdepth:
|
||||
for k in node.ant_iter(accept=accept, maxdepth=maxdepth - 1, pats=npats, dir=dir, src=src, remove=remove):
|
||||
yield k
|
||||
raise StopIteration
|
||||
|
||||
def ant_glob(self, *k, **kw):
|
||||
"""
|
||||
This method is used for finding files across folders. It behaves like ant patterns:
|
||||
|
||||
* ``**/*`` find all files recursively
|
||||
* ``**/*.class`` find all files ending by .class
|
||||
* ``..`` find files having two dot characters
|
||||
|
||||
For example::
|
||||
|
||||
def configure(cfg):
|
||||
cfg.path.ant_glob('**/*.cpp') # find all .cpp files
|
||||
cfg.root.ant_glob('etc/*.txt') # using the filesystem root can be slow
|
||||
cfg.path.ant_glob('*.cpp', excl=['*.c'], src=True, dir=False)
|
||||
|
||||
For more information see http://ant.apache.org/manual/dirtasks.html
|
||||
|
||||
The nodes that correspond to files and folders that do not exist will be removed. To prevent this
|
||||
behaviour, pass 'remove=False'
|
||||
|
||||
:param incl: ant patterns or list of patterns to include
|
||||
:type incl: string or list of strings
|
||||
:param excl: ant patterns or list of patterns to exclude
|
||||
:type excl: string or list of strings
|
||||
:param dir: return folders too (False by default)
|
||||
:type dir: bool
|
||||
:param src: return files (True by default)
|
||||
:type src: bool
|
||||
:param remove: remove files/folders that do not exist (True by default)
|
||||
:type remove: bool
|
||||
:param maxdepth: maximum depth of recursion
|
||||
:type maxdepth: int
|
||||
:param ignorecase: ignore case while matching (False by default)
|
||||
:type ignorecase: bool
|
||||
"""
|
||||
|
||||
src = kw.get('src', True)
|
||||
dir = kw.get('dir', False)
|
||||
|
||||
excl = kw.get('excl', exclude_regs)
|
||||
incl = k and k[0] or kw.get('incl', '**')
|
||||
reflags = kw.get('ignorecase', 0) and re.I
|
||||
|
||||
def to_pat(s):
|
||||
lst = Utils.to_list(s)
|
||||
ret = []
|
||||
for x in lst:
|
||||
x = x.replace('\\', '/').replace('//', '/')
|
||||
if x.endswith('/'):
|
||||
x += '**'
|
||||
lst2 = x.split('/')
|
||||
accu = []
|
||||
for k in lst2:
|
||||
if k == '**':
|
||||
accu.append(k)
|
||||
else:
|
||||
k = k.replace('.', '[.]').replace('*','.*').replace('?', '.').replace('+', '\\+')
|
||||
k = '^%s$' % k
|
||||
try:
|
||||
#print "pattern", k
|
||||
accu.append(re.compile(k, flags=reflags))
|
||||
except Exception as e:
|
||||
raise Errors.WafError("Invalid pattern: %s" % k, e)
|
||||
ret.append(accu)
|
||||
return ret
|
||||
|
||||
def filtre(name, nn):
|
||||
ret = []
|
||||
for lst in nn:
|
||||
if not lst:
|
||||
pass
|
||||
elif lst[0] == '**':
|
||||
ret.append(lst)
|
||||
if len(lst) > 1:
|
||||
if lst[1].match(name):
|
||||
ret.append(lst[2:])
|
||||
else:
|
||||
ret.append([])
|
||||
elif lst[0].match(name):
|
||||
ret.append(lst[1:])
|
||||
return ret
|
||||
|
||||
def accept(name, pats):
|
||||
nacc = filtre(name, pats[0])
|
||||
nrej = filtre(name, pats[1])
|
||||
if [] in nrej:
|
||||
nacc = []
|
||||
return [nacc, nrej]
|
||||
|
||||
ret = [x for x in self.ant_iter(accept=accept, pats=[to_pat(incl), to_pat(excl)], maxdepth=25, dir=dir, src=src, remove=kw.get('remove', True))]
|
||||
if kw.get('flat', False):
|
||||
return ' '.join([x.path_from(self) for x in ret])
|
||||
|
||||
return ret
|
||||
|
||||
# --------------------------------------------------------------------------------
|
||||
# the following methods require the source/build folders (bld.srcnode/bld.bldnode)
|
||||
# using a subclass is a possibility, but is that really necessary?
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
def is_src(self):
|
||||
"""
|
||||
True if the node is below the source directory
|
||||
note: !is_src does not imply is_bld()
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
cur = self
|
||||
x = id(self.ctx.srcnode)
|
||||
y = id(self.ctx.bldnode)
|
||||
while cur.parent:
|
||||
if id(cur) == y:
|
||||
return False
|
||||
if id(cur) == x:
|
||||
return True
|
||||
cur = cur.parent
|
||||
return False
|
||||
|
||||
def is_bld(self):
|
||||
"""
|
||||
True if the node is below the build directory
|
||||
note: !is_bld does not imply is_src
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
cur = self
|
||||
y = id(self.ctx.bldnode)
|
||||
while cur.parent:
|
||||
if id(cur) == y:
|
||||
return True
|
||||
cur = cur.parent
|
||||
return False
|
||||
|
||||
def get_src(self):
|
||||
"""
|
||||
Return the equivalent src node (or self if not possible)
|
||||
|
||||
:rtype: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
cur = self
|
||||
x = id(self.ctx.srcnode)
|
||||
y = id(self.ctx.bldnode)
|
||||
lst = []
|
||||
while cur.parent:
|
||||
if id(cur) == y:
|
||||
lst.reverse()
|
||||
return self.ctx.srcnode.make_node(lst)
|
||||
if id(cur) == x:
|
||||
return self
|
||||
lst.append(cur.name)
|
||||
cur = cur.parent
|
||||
return self
|
||||
|
||||
def get_bld(self):
|
||||
"""
|
||||
Return the equivalent bld node (or self if not possible)
|
||||
|
||||
:rtype: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
cur = self
|
||||
x = id(self.ctx.srcnode)
|
||||
y = id(self.ctx.bldnode)
|
||||
lst = []
|
||||
while cur.parent:
|
||||
if id(cur) == y:
|
||||
return self
|
||||
if id(cur) == x:
|
||||
lst.reverse()
|
||||
return self.ctx.bldnode.make_node(lst)
|
||||
lst.append(cur.name)
|
||||
cur = cur.parent
|
||||
# the file is external to the current project, make a fake root in the current build directory
|
||||
lst.reverse()
|
||||
if lst and Utils.is_win32 and len(lst[0]) == 2 and lst[0].endswith(':'):
|
||||
lst[0] = lst[0][0]
|
||||
return self.ctx.bldnode.make_node(['__root__'] + lst)
|
||||
|
||||
def find_resource(self, lst):
|
||||
"""
|
||||
Try to find a declared build node or a source file
|
||||
|
||||
:param lst: path
|
||||
:type lst: string or list of string
|
||||
"""
|
||||
if isinstance(lst, str):
|
||||
lst = [x for x in split_path(lst) if x and x != '.']
|
||||
|
||||
node = self.get_bld().search_node(lst)
|
||||
if not node:
|
||||
self = self.get_src()
|
||||
node = self.find_node(lst)
|
||||
if node:
|
||||
if os.path.isdir(node.abspath()):
|
||||
return None
|
||||
return node
|
||||
|
||||
def find_or_declare(self, lst):
|
||||
"""
|
||||
if 'self' is in build directory, try to return an existing node
|
||||
if no node is found, go to the source directory
|
||||
try to find an existing node in the source directory
|
||||
if no node is found, create it in the build directory
|
||||
|
||||
:param lst: path
|
||||
:type lst: string or list of string
|
||||
"""
|
||||
if isinstance(lst, str):
|
||||
lst = [x for x in split_path(lst) if x and x != '.']
|
||||
|
||||
node = self.get_bld().search_node(lst)
|
||||
if node:
|
||||
if not os.path.isfile(node.abspath()):
|
||||
node.sig = None
|
||||
node.parent.mkdir()
|
||||
return node
|
||||
self = self.get_src()
|
||||
node = self.find_node(lst)
|
||||
if node:
|
||||
if not os.path.isfile(node.abspath()):
|
||||
node.sig = None
|
||||
node.parent.mkdir()
|
||||
return node
|
||||
node = self.get_bld().make_node(lst)
|
||||
node.parent.mkdir()
|
||||
return node
|
||||
|
||||
def find_dir(self, lst):
|
||||
"""
|
||||
Search for a folder in the filesystem
|
||||
|
||||
:param lst: path
|
||||
:type lst: string or list of string
|
||||
"""
|
||||
if isinstance(lst, str):
|
||||
lst = [x for x in split_path(lst) if x and x != '.']
|
||||
|
||||
node = self.find_node(lst)
|
||||
try:
|
||||
if not os.path.isdir(node.abspath()):
|
||||
return None
|
||||
except (OSError, AttributeError):
|
||||
# the node might be None, and raise an AttributeError
|
||||
return None
|
||||
return node
|
||||
|
||||
# helpers for building things
|
||||
def change_ext(self, ext, ext_in=None):
|
||||
"""
|
||||
:return: A build node of the same path, but with a different extension
|
||||
:rtype: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
name = self.name
|
||||
if ext_in is None:
|
||||
k = name.rfind('.')
|
||||
if k >= 0:
|
||||
name = name[:k] + ext
|
||||
else:
|
||||
name = name + ext
|
||||
else:
|
||||
name = name[:- len(ext_in)] + ext
|
||||
|
||||
return self.parent.find_or_declare([name])
|
||||
|
||||
def nice_path(self, env=None):
|
||||
"""
|
||||
Return the path seen from the launch directory.
|
||||
Can be used for opening files easily (copy-paste in the console).
|
||||
"""
|
||||
return self.path_from(self.ctx.launch_node())
|
||||
|
||||
def bldpath(self):
|
||||
"Path seen from the build directory default/src/foo.cpp"
|
||||
return self.path_from(self.ctx.bldnode)
|
||||
|
||||
def srcpath(self):
|
||||
"Path seen from the source directory ../src/foo.cpp"
|
||||
return self.path_from(self.ctx.srcnode)
|
||||
|
||||
def relpath(self):
|
||||
"If a file in the build directory, bldpath, else srcpath"
|
||||
cur = self
|
||||
x = id(self.ctx.bldnode)
|
||||
while cur.parent:
|
||||
if id(cur) == x:
|
||||
return self.bldpath()
|
||||
cur = cur.parent
|
||||
return self.srcpath()
|
||||
|
||||
def bld_dir(self):
|
||||
"Build path without the file name"
|
||||
return self.parent.bldpath()
|
||||
|
||||
def bld_base(self):
|
||||
"Build path without the extension: src/dir/foo(.cpp)"
|
||||
s = os.path.splitext(self.name)[0]
|
||||
return self.bld_dir() + os.sep + s
|
||||
|
||||
def get_bld_sig(self):
|
||||
"""
|
||||
Node signature, assuming the file is in the build directory
|
||||
"""
|
||||
try:
|
||||
return self.cache_sig
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if not self.is_bld() or self.ctx.bldnode is self.ctx.srcnode:
|
||||
self.sig = Utils.h_file(self.abspath())
|
||||
self.cache_sig = ret = self.sig
|
||||
return ret
|
||||
|
||||
|
||||
# TODO Waf 1.8
|
||||
search = search_node
|
||||
|
||||
pickle_lock = Utils.threading.Lock()
|
||||
"""Lock mandatory for thread-safe node serialization"""
|
||||
|
||||
class Nod3(Node):
|
||||
"""Mandatory subclass for thread-safe node serialization"""
|
||||
pass # do not remove
|
||||
|
||||
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Scott Newton, 2005 (scottn)
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
Support for waf command-line options
|
||||
|
||||
Provides default command-line options,
|
||||
as well as custom ones, used by the ``options`` wscript function.
|
||||
|
||||
"""
|
||||
|
||||
import os, tempfile, optparse, sys, re
|
||||
from waflib import Logs, Utils, Context
|
||||
|
||||
cmds = 'distclean configure build install clean uninstall check dist distcheck'.split()
|
||||
"""
|
||||
Constant representing the default waf commands displayed in::
|
||||
|
||||
$ waf --help
|
||||
|
||||
"""
|
||||
|
||||
options = {}
|
||||
"""
|
||||
A dictionary representing the command-line options::
|
||||
|
||||
$ waf --foo=bar
|
||||
|
||||
"""
|
||||
|
||||
commands = []
|
||||
"""
|
||||
List of commands to execute extracted from the command-line. This list is consumed during the execution, see :py:func:`waflib.Scripting.run_commands`.
|
||||
"""
|
||||
|
||||
lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform)
|
||||
try: cache_global = os.path.abspath(os.environ['WAFCACHE'])
|
||||
except KeyError: cache_global = ''
|
||||
platform = Utils.unversioned_sys_platform()
|
||||
|
||||
|
||||
class opt_parser(optparse.OptionParser):
|
||||
"""
|
||||
Command-line options parser.
|
||||
"""
|
||||
def __init__(self, ctx):
|
||||
optparse.OptionParser.__init__(self, conflict_handler="resolve", version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION))
|
||||
|
||||
self.formatter.width = Logs.get_term_cols()
|
||||
p = self.add_option
|
||||
self.ctx = ctx
|
||||
|
||||
jobs = ctx.jobs()
|
||||
p('-j', '--jobs', dest='jobs', default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs)
|
||||
p('-k', '--keep', dest='keep', default=0, action='count', help='keep running happily even if errors are found')
|
||||
p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]')
|
||||
p('--nocache', dest='nocache', default=False, action='store_true', help='ignore the WAFCACHE (if set)')
|
||||
p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)')
|
||||
|
||||
gr = optparse.OptionGroup(self, 'configure options')
|
||||
self.add_option_group(gr)
|
||||
|
||||
gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out')
|
||||
gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top')
|
||||
|
||||
default_prefix = os.environ.get('PREFIX')
|
||||
if not default_prefix:
|
||||
if platform == 'win32':
|
||||
d = tempfile.gettempdir()
|
||||
default_prefix = d[0].upper() + d[1:]
|
||||
# win32 preserves the case, but gettempdir does not
|
||||
else:
|
||||
default_prefix = '/usr/local/'
|
||||
gr.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: %r]' % default_prefix)
|
||||
gr.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing')
|
||||
|
||||
|
||||
gr = optparse.OptionGroup(self, 'build and install options')
|
||||
self.add_option_group(gr)
|
||||
|
||||
gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output')
|
||||
gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"')
|
||||
|
||||
gr = optparse.OptionGroup(self, 'step options')
|
||||
self.add_option_group(gr)
|
||||
gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
|
||||
|
||||
default_destdir = os.environ.get('DESTDIR', '')
|
||||
gr = optparse.OptionGroup(self, 'install/uninstall options')
|
||||
self.add_option_group(gr)
|
||||
gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir')
|
||||
gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation')
|
||||
|
||||
gr.add_option('--distcheck-args', help='arguments to pass to distcheck', default=None, action='store')
|
||||
|
||||
def get_usage(self):
|
||||
"""
|
||||
Return the message to print on ``waf --help``
|
||||
"""
|
||||
cmds_str = {}
|
||||
for cls in Context.classes:
|
||||
if not cls.cmd or cls.cmd == 'options':
|
||||
continue
|
||||
|
||||
s = cls.__doc__ or ''
|
||||
cmds_str[cls.cmd] = s
|
||||
|
||||
if Context.g_module:
|
||||
for (k, v) in Context.g_module.__dict__.items():
|
||||
if k in ['options', 'init', 'shutdown']:
|
||||
continue
|
||||
|
||||
if type(v) is type(Context.create_context):
|
||||
if v.__doc__ and not k.startswith('_'):
|
||||
cmds_str[k] = v.__doc__
|
||||
|
||||
just = 0
|
||||
for k in cmds_str:
|
||||
just = max(just, len(k))
|
||||
|
||||
lst = [' %s: %s' % (k.ljust(just), v) for (k, v) in cmds_str.items()]
|
||||
lst.sort()
|
||||
ret = '\n'.join(lst)
|
||||
|
||||
return '''waf [commands] [options]
|
||||
|
||||
Main commands (example: ./waf build -j4)
|
||||
%s
|
||||
''' % ret
|
||||
|
||||
|
||||
class OptionsContext(Context.Context):
|
||||
"""
|
||||
Collect custom options from wscript files and parses the command line.
|
||||
Set the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
|
||||
"""
|
||||
|
||||
cmd = 'options'
|
||||
fun = 'options'
|
||||
|
||||
def __init__(self, **kw):
|
||||
super(OptionsContext, self).__init__(**kw)
|
||||
|
||||
self.parser = opt_parser(self)
|
||||
"""Instance of :py:class:`waflib.Options.opt_parser`"""
|
||||
|
||||
self.option_groups = {}
|
||||
|
||||
def jobs(self):
|
||||
"""
|
||||
Find the amount of cpu cores to set the default amount of tasks executed in parallel. At
|
||||
runtime the options can be obtained from :py:const:`waflib.Options.options` ::
|
||||
|
||||
from waflib.Options import options
|
||||
njobs = options.jobs
|
||||
|
||||
:return: the amount of cpu cores
|
||||
:rtype: int
|
||||
"""
|
||||
count = int(os.environ.get('JOBS', 0))
|
||||
if count < 1:
|
||||
if 'NUMBER_OF_PROCESSORS' in os.environ:
|
||||
# on Windows, use the NUMBER_OF_PROCESSORS environment variable
|
||||
count = int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
|
||||
else:
|
||||
# on everything else, first try the POSIX sysconf values
|
||||
if hasattr(os, 'sysconf_names'):
|
||||
if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
|
||||
count = int(os.sysconf('SC_NPROCESSORS_ONLN'))
|
||||
elif 'SC_NPROCESSORS_CONF' in os.sysconf_names:
|
||||
count = int(os.sysconf('SC_NPROCESSORS_CONF'))
|
||||
if not count and os.name not in ('nt', 'java'):
|
||||
try:
|
||||
tmp = self.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet=0)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
if re.match('^[0-9]+$', tmp):
|
||||
count = int(tmp)
|
||||
if count < 1:
|
||||
count = 1
|
||||
elif count > 1024:
|
||||
count = 1024
|
||||
return count
|
||||
|
||||
def add_option(self, *k, **kw):
|
||||
"""
|
||||
Wrapper for optparse.add_option::
|
||||
|
||||
def options(ctx):
|
||||
ctx.add_option('-u', '--use', dest='use', default=False, action='store_true',
|
||||
help='a boolean option')
|
||||
"""
|
||||
return self.parser.add_option(*k, **kw)
|
||||
|
||||
def add_option_group(self, *k, **kw):
|
||||
"""
|
||||
Wrapper for optparse.add_option_group::
|
||||
|
||||
def options(ctx):
|
||||
gr = ctx.add_option_group('some options')
|
||||
gr.add_option('-u', '--use', dest='use', default=False, action='store_true')
|
||||
"""
|
||||
try:
|
||||
gr = self.option_groups[k[0]]
|
||||
except KeyError:
|
||||
gr = self.parser.add_option_group(*k, **kw)
|
||||
self.option_groups[k[0]] = gr
|
||||
return gr
|
||||
|
||||
def get_option_group(self, opt_str):
|
||||
"""
|
||||
Wrapper for optparse.get_option_group::
|
||||
|
||||
def options(ctx):
|
||||
gr = ctx.get_option_group('configure options')
|
||||
gr.add_option('-o', '--out', action='store', default='',
|
||||
help='build dir for the project', dest='out')
|
||||
|
||||
"""
|
||||
try:
|
||||
return self.option_groups[opt_str]
|
||||
except KeyError:
|
||||
for group in self.parser.option_groups:
|
||||
if group.title == opt_str:
|
||||
return group
|
||||
return None
|
||||
|
||||
def parse_args(self, _args=None):
|
||||
"""
|
||||
Parse arguments from a list (not bound to the command-line).
|
||||
|
||||
:param _args: arguments
|
||||
:type _args: list of strings
|
||||
"""
|
||||
global options, commands
|
||||
(options, leftover_args) = self.parser.parse_args(args=_args)
|
||||
commands = leftover_args
|
||||
|
||||
if options.destdir:
|
||||
options.destdir = os.path.abspath(os.path.expanduser(options.destdir))
|
||||
|
||||
if options.verbose >= 1:
|
||||
self.load('errcheck')
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
See :py:func:`waflib.Context.Context.execute`
|
||||
"""
|
||||
super(OptionsContext, self).execute()
|
||||
self.parse_args()
|
||||
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
Runner.py: Task scheduling and execution
|
||||
|
||||
"""
|
||||
|
||||
import random, atexit
|
||||
try:
|
||||
from queue import Queue
|
||||
except ImportError:
|
||||
from Queue import Queue
|
||||
from waflib import Utils, Task, Errors, Logs
|
||||
|
||||
GAP = 10
|
||||
"""
|
||||
Wait for free tasks if there are at least ``GAP * njobs`` in queue
|
||||
"""
|
||||
|
||||
class TaskConsumer(Utils.threading.Thread):
|
||||
"""
|
||||
Task consumers belong to a pool of workers
|
||||
|
||||
They wait for tasks in the queue and then use ``task.process(...)``
|
||||
"""
|
||||
def __init__(self):
|
||||
Utils.threading.Thread.__init__(self)
|
||||
self.ready = Queue()
|
||||
"""
|
||||
Obtain :py:class:`waflib.Task.TaskBase` instances from this queue.
|
||||
"""
|
||||
self.setDaemon(1)
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Loop over the tasks to execute
|
||||
"""
|
||||
try:
|
||||
self.loop()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def loop(self):
|
||||
"""
|
||||
Obtain tasks from :py:attr:`waflib.Runner.TaskConsumer.ready` and call
|
||||
:py:meth:`waflib.Task.TaskBase.process`. If the object is a function, execute it.
|
||||
"""
|
||||
while 1:
|
||||
tsk = self.ready.get()
|
||||
if not isinstance(tsk, Task.TaskBase):
|
||||
tsk(self)
|
||||
else:
|
||||
tsk.process()
|
||||
|
||||
pool = Queue()
|
||||
"""
|
||||
Pool of task consumer objects
|
||||
"""
|
||||
|
||||
def get_pool():
|
||||
"""
|
||||
Obtain a task consumer from :py:attr:`waflib.Runner.pool`.
|
||||
Do not forget to put it back by using :py:func:`waflib.Runner.put_pool`
|
||||
and reset properly (original waiting queue).
|
||||
|
||||
:rtype: :py:class:`waflib.Runner.TaskConsumer`
|
||||
"""
|
||||
try:
|
||||
return pool.get(False)
|
||||
except Exception:
|
||||
return TaskConsumer()
|
||||
|
||||
def put_pool(x):
|
||||
"""
|
||||
Return a task consumer to the thread pool :py:attr:`waflib.Runner.pool`
|
||||
|
||||
:param x: task consumer object
|
||||
:type x: :py:class:`waflib.Runner.TaskConsumer`
|
||||
"""
|
||||
pool.put(x)
|
||||
|
||||
def _free_resources():
|
||||
global pool
|
||||
lst = []
|
||||
while pool.qsize():
|
||||
lst.append(pool.get())
|
||||
for x in lst:
|
||||
x.ready.put(None)
|
||||
for x in lst:
|
||||
x.join()
|
||||
pool = None
|
||||
atexit.register(_free_resources)
|
||||
|
||||
class Parallel(object):
|
||||
"""
|
||||
Schedule the tasks obtained from the build context for execution.
|
||||
"""
|
||||
def __init__(self, bld, j=2):
|
||||
"""
|
||||
The initialization requires a build context reference
|
||||
for computing the total number of jobs.
|
||||
"""
|
||||
|
||||
self.numjobs = j
|
||||
"""
|
||||
Number of consumers in the pool
|
||||
"""
|
||||
|
||||
self.bld = bld
|
||||
"""
|
||||
Instance of :py:class:`waflib.Build.BuildContext`
|
||||
"""
|
||||
|
||||
self.outstanding = []
|
||||
"""List of :py:class:`waflib.Task.TaskBase` that may be ready to be executed"""
|
||||
|
||||
self.frozen = []
|
||||
"""List of :py:class:`waflib.Task.TaskBase` that cannot be executed immediately"""
|
||||
|
||||
self.out = Queue(0)
|
||||
"""List of :py:class:`waflib.Task.TaskBase` returned by the task consumers"""
|
||||
|
||||
self.count = 0
|
||||
"""Amount of tasks that may be processed by :py:class:`waflib.Runner.TaskConsumer`"""
|
||||
|
||||
self.processed = 1
|
||||
"""Amount of tasks processed"""
|
||||
|
||||
self.stop = False
|
||||
"""Error flag to stop the build"""
|
||||
|
||||
self.error = []
|
||||
"""Tasks that could not be executed"""
|
||||
|
||||
self.biter = None
|
||||
"""Task iterator which must give groups of parallelizable tasks when calling ``next()``"""
|
||||
|
||||
self.dirty = False
|
||||
"""Flag to indicate that tasks have been executed, and that the build cache must be saved (call :py:meth:`waflib.Build.BuildContext.store`)"""
|
||||
|
||||
def get_next_task(self):
|
||||
"""
|
||||
Obtain the next task to execute.
|
||||
|
||||
:rtype: :py:class:`waflib.Task.TaskBase`
|
||||
"""
|
||||
if not self.outstanding:
|
||||
return None
|
||||
return self.outstanding.pop(0)
|
||||
|
||||
def postpone(self, tsk):
|
||||
"""
|
||||
A task cannot be executed at this point, put it in the list :py:attr:`waflib.Runner.Parallel.frozen`.
|
||||
|
||||
:param tsk: task
|
||||
:type tsk: :py:class:`waflib.Task.TaskBase`
|
||||
"""
|
||||
if random.randint(0, 1):
|
||||
self.frozen.insert(0, tsk)
|
||||
else:
|
||||
self.frozen.append(tsk)
|
||||
|
||||
def refill_task_list(self):
|
||||
"""
|
||||
Put the next group of tasks to execute in :py:attr:`waflib.Runner.Parallel.outstanding`.
|
||||
"""
|
||||
while self.count > self.numjobs * GAP:
|
||||
self.get_out()
|
||||
|
||||
while not self.outstanding:
|
||||
if self.count:
|
||||
self.get_out()
|
||||
elif self.frozen:
|
||||
try:
|
||||
cond = self.deadlock == self.processed
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if cond:
|
||||
msg = 'check the build order for the tasks'
|
||||
for tsk in self.frozen:
|
||||
if not tsk.run_after:
|
||||
msg = 'check the methods runnable_status'
|
||||
break
|
||||
lst = []
|
||||
for tsk in self.frozen:
|
||||
lst.append('%s\t-> %r' % (repr(tsk), [id(x) for x in tsk.run_after]))
|
||||
raise Errors.WafError('Deadlock detected: %s%s' % (msg, ''.join(lst)))
|
||||
self.deadlock = self.processed
|
||||
|
||||
if self.frozen:
|
||||
self.outstanding += self.frozen
|
||||
self.frozen = []
|
||||
elif not self.count:
|
||||
self.outstanding.extend(next(self.biter))
|
||||
self.total = self.bld.total()
|
||||
break
|
||||
|
||||
def add_more_tasks(self, tsk):
|
||||
"""
|
||||
Tasks may be added dynamically during the build by binding them to the task :py:attr:`waflib.Task.TaskBase.more_tasks`
|
||||
|
||||
:param tsk: task
|
||||
:type tsk: :py:attr:`waflib.Task.TaskBase`
|
||||
"""
|
||||
if getattr(tsk, 'more_tasks', None):
|
||||
self.outstanding += tsk.more_tasks
|
||||
self.total += len(tsk.more_tasks)
|
||||
|
||||
def get_out(self):
|
||||
"""
|
||||
Obtain one task returned from the task consumers, and update the task count. Add more tasks if necessary through
|
||||
:py:attr:`waflib.Runner.Parallel.add_more_tasks`.
|
||||
|
||||
:rtype: :py:attr:`waflib.Task.TaskBase`
|
||||
"""
|
||||
tsk = self.out.get()
|
||||
if not self.stop:
|
||||
self.add_more_tasks(tsk)
|
||||
self.count -= 1
|
||||
self.dirty = True
|
||||
return tsk
|
||||
|
||||
def error_handler(self, tsk):
|
||||
"""
|
||||
Called when a task cannot be executed. The flag :py:attr:`waflib.Runner.Parallel.stop` is set, unless
|
||||
the build is executed with::
|
||||
|
||||
$ waf build -k
|
||||
|
||||
:param tsk: task
|
||||
:type tsk: :py:attr:`waflib.Task.TaskBase`
|
||||
"""
|
||||
if not self.bld.keep:
|
||||
self.stop = True
|
||||
self.error.append(tsk)
|
||||
|
||||
def add_task(self, tsk):
|
||||
"""
|
||||
Pass a task to a consumer.
|
||||
|
||||
:param tsk: task
|
||||
:type tsk: :py:attr:`waflib.Task.TaskBase`
|
||||
"""
|
||||
try:
|
||||
self.pool
|
||||
except AttributeError:
|
||||
self.init_task_pool()
|
||||
self.ready.put(tsk)
|
||||
|
||||
def init_task_pool(self):
|
||||
# lazy creation, and set a common pool for all task consumers
|
||||
pool = self.pool = [get_pool() for i in range(self.numjobs)]
|
||||
self.ready = Queue(0)
|
||||
def setq(consumer):
|
||||
consumer.ready = self.ready
|
||||
for x in pool:
|
||||
x.ready.put(setq)
|
||||
return pool
|
||||
|
||||
def free_task_pool(self):
|
||||
# return the consumers, setting a different queue for each of them
|
||||
def setq(consumer):
|
||||
consumer.ready = Queue(0)
|
||||
self.out.put(self)
|
||||
try:
|
||||
pool = self.pool
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
for x in pool:
|
||||
self.ready.put(setq)
|
||||
for x in pool:
|
||||
self.get_out()
|
||||
for x in pool:
|
||||
put_pool(x)
|
||||
self.pool = []
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Give tasks to :py:class:`waflib.Runner.TaskConsumer` instances until the build finishes or the ``stop`` flag is set.
|
||||
If only one job is used, then execute the tasks one by one, without consumers.
|
||||
"""
|
||||
|
||||
self.total = self.bld.total()
|
||||
|
||||
while not self.stop:
|
||||
|
||||
self.refill_task_list()
|
||||
|
||||
# consider the next task
|
||||
tsk = self.get_next_task()
|
||||
if not tsk:
|
||||
if self.count:
|
||||
# tasks may add new ones after they are run
|
||||
continue
|
||||
else:
|
||||
# no tasks to run, no tasks running, time to exit
|
||||
break
|
||||
|
||||
if tsk.hasrun:
|
||||
# if the task is marked as "run", just skip it
|
||||
self.processed += 1
|
||||
continue
|
||||
|
||||
if self.stop: # stop immediately after a failure was detected
|
||||
break
|
||||
|
||||
try:
|
||||
st = tsk.runnable_status()
|
||||
except Exception:
|
||||
self.processed += 1
|
||||
# TODO waf 1.7 this piece of code should go in the error_handler
|
||||
tsk.err_msg = Utils.ex_stack()
|
||||
if not self.stop and self.bld.keep:
|
||||
tsk.hasrun = Task.SKIPPED
|
||||
if self.bld.keep == 1:
|
||||
# if -k stop at the first exception, if -kk try to go as far as possible
|
||||
if Logs.verbose > 1 or not self.error:
|
||||
self.error.append(tsk)
|
||||
self.stop = True
|
||||
else:
|
||||
if Logs.verbose > 1:
|
||||
self.error.append(tsk)
|
||||
continue
|
||||
tsk.hasrun = Task.EXCEPTION
|
||||
self.error_handler(tsk)
|
||||
continue
|
||||
|
||||
if st == Task.ASK_LATER:
|
||||
self.postpone(tsk)
|
||||
elif st == Task.SKIP_ME:
|
||||
self.processed += 1
|
||||
tsk.hasrun = Task.SKIPPED
|
||||
self.add_more_tasks(tsk)
|
||||
else:
|
||||
# run me: put the task in ready queue
|
||||
tsk.position = (self.processed, self.total)
|
||||
self.count += 1
|
||||
tsk.master = self
|
||||
self.processed += 1
|
||||
|
||||
if self.numjobs == 1:
|
||||
tsk.process()
|
||||
else:
|
||||
self.add_task(tsk)
|
||||
|
||||
# self.count represents the tasks that have been made available to the consumer threads
|
||||
# collect all the tasks after an error else the message may be incomplete
|
||||
while self.error and self.count:
|
||||
self.get_out()
|
||||
|
||||
#print loop
|
||||
assert (self.count == 0 or self.stop)
|
||||
|
||||
# free the task pool, if any
|
||||
self.free_task_pool()
|
||||
|
||||
+579
@@ -0,0 +1,579 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"Module called for configuring, compiling and installing targets"
|
||||
|
||||
import os, shlex, shutil, traceback, errno, sys, stat
|
||||
from waflib import Utils, Configure, Logs, Options, ConfigSet, Context, Errors, Build, Node
|
||||
|
||||
build_dir_override = None
|
||||
|
||||
no_climb_commands = ['configure']
|
||||
|
||||
default_cmd = "build"
|
||||
|
||||
def waf_entry_point(current_directory, version, wafdir):
|
||||
"""
|
||||
This is the main entry point, all Waf execution starts here.
|
||||
|
||||
:param current_directory: absolute path representing the current directory
|
||||
:type current_directory: string
|
||||
:param version: version number
|
||||
:type version: string
|
||||
:param wafdir: absolute path representing the directory of the waf library
|
||||
:type wafdir: string
|
||||
"""
|
||||
|
||||
Logs.init_log()
|
||||
|
||||
if Context.WAFVERSION != version:
|
||||
Logs.error('Waf script %r and library %r do not match (directory %r)' % (version, Context.WAFVERSION, wafdir))
|
||||
sys.exit(1)
|
||||
|
||||
if '--version' in sys.argv:
|
||||
Context.run_dir = current_directory
|
||||
ctx = Context.create_context('options')
|
||||
ctx.curdir = current_directory
|
||||
ctx.parse_args()
|
||||
sys.exit(0)
|
||||
|
||||
Context.waf_dir = wafdir
|
||||
Context.launch_dir = current_directory
|
||||
|
||||
# if 'configure' is in the commands, do not search any further
|
||||
no_climb = os.environ.get('NOCLIMB', None)
|
||||
if not no_climb:
|
||||
for k in no_climb_commands:
|
||||
if k in sys.argv:
|
||||
no_climb = True
|
||||
break
|
||||
|
||||
# try to find a lock file (if the project was configured)
|
||||
# at the same time, store the first wscript file seen
|
||||
cur = current_directory
|
||||
while cur:
|
||||
lst = os.listdir(cur)
|
||||
if Options.lockfile in lst:
|
||||
env = ConfigSet.ConfigSet()
|
||||
try:
|
||||
env.load(os.path.join(cur, Options.lockfile))
|
||||
ino = os.stat(cur)[stat.ST_INO]
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
# check if the folder was not moved
|
||||
for x in [env.run_dir, env.top_dir, env.out_dir]:
|
||||
if Utils.is_win32:
|
||||
if cur == x:
|
||||
load = True
|
||||
break
|
||||
else:
|
||||
# if the filesystem features symlinks, compare the inode numbers
|
||||
try:
|
||||
ino2 = os.stat(x)[stat.ST_INO]
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
if ino == ino2:
|
||||
load = True
|
||||
break
|
||||
else:
|
||||
Logs.warn('invalid lock file in %s' % cur)
|
||||
load = False
|
||||
|
||||
if load:
|
||||
Context.run_dir = env.run_dir
|
||||
Context.top_dir = env.top_dir
|
||||
Context.out_dir = env.out_dir
|
||||
break
|
||||
|
||||
if not Context.run_dir:
|
||||
if Context.WSCRIPT_FILE in lst:
|
||||
Context.run_dir = cur
|
||||
|
||||
next = os.path.dirname(cur)
|
||||
if next == cur:
|
||||
break
|
||||
cur = next
|
||||
|
||||
if no_climb:
|
||||
break
|
||||
|
||||
if not Context.run_dir:
|
||||
if '-h' in sys.argv or '--help' in sys.argv:
|
||||
Logs.warn('No wscript file found: the help message may be incomplete')
|
||||
Context.run_dir = current_directory
|
||||
ctx = Context.create_context('options')
|
||||
ctx.curdir = current_directory
|
||||
ctx.parse_args()
|
||||
sys.exit(0)
|
||||
Logs.error('Waf: Run from a directory containing a file named %r' % Context.WSCRIPT_FILE)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
os.chdir(Context.run_dir)
|
||||
except OSError:
|
||||
Logs.error('Waf: The folder %r is unreadable' % Context.run_dir)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
set_main_module(Context.run_dir + os.sep + Context.WSCRIPT_FILE)
|
||||
except Errors.WafError as e:
|
||||
Logs.pprint('RED', e.verbose_msg)
|
||||
Logs.error(str(e))
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
Logs.error('Waf: The wscript in %r is unreadable' % Context.run_dir, e)
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
sys.exit(2)
|
||||
|
||||
"""
|
||||
import cProfile, pstats
|
||||
cProfile.runctx("from waflib import Scripting; Scripting.run_commands()", {}, {}, 'profi.txt')
|
||||
p = pstats.Stats('profi.txt')
|
||||
p.sort_stats('time').print_stats(25) # or 'cumulative'
|
||||
"""
|
||||
try:
|
||||
run_commands()
|
||||
except Errors.WafError as e:
|
||||
if Logs.verbose > 1:
|
||||
Logs.pprint('RED', e.verbose_msg)
|
||||
Logs.error(e.msg)
|
||||
sys.exit(1)
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
sys.exit(2)
|
||||
except KeyboardInterrupt:
|
||||
Logs.pprint('RED', 'Interrupted')
|
||||
sys.exit(68)
|
||||
#"""
|
||||
|
||||
def set_main_module(file_path):
|
||||
"""
|
||||
Read the main wscript file into :py:const:`waflib.Context.Context.g_module` and
|
||||
bind default functions such as ``init``, ``dist``, ``distclean`` if not defined.
|
||||
Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.
|
||||
|
||||
:param file_path: absolute path representing the top-level wscript file
|
||||
:type file_path: string
|
||||
"""
|
||||
Context.g_module = Context.load_module(file_path)
|
||||
Context.g_module.root_path = file_path
|
||||
|
||||
# note: to register the module globally, use the following:
|
||||
# sys.modules['wscript_main'] = g_module
|
||||
|
||||
def set_def(obj):
|
||||
name = obj.__name__
|
||||
if not name in Context.g_module.__dict__:
|
||||
setattr(Context.g_module, name, obj)
|
||||
for k in [update, dist, distclean, distcheck, update]:
|
||||
set_def(k)
|
||||
# add dummy init and shutdown functions if they're not defined
|
||||
if not 'init' in Context.g_module.__dict__:
|
||||
Context.g_module.init = Utils.nada
|
||||
if not 'shutdown' in Context.g_module.__dict__:
|
||||
Context.g_module.shutdown = Utils.nada
|
||||
if not 'options' in Context.g_module.__dict__:
|
||||
Context.g_module.options = Utils.nada
|
||||
|
||||
def parse_options():
|
||||
"""
|
||||
Parse the command-line options and initialize the logging system.
|
||||
Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.
|
||||
"""
|
||||
Context.create_context('options').execute()
|
||||
|
||||
if not Options.commands:
|
||||
Options.commands = [default_cmd]
|
||||
Options.commands = [x for x in Options.commands if x != 'options'] # issue 1076
|
||||
|
||||
# process some internal Waf options
|
||||
Logs.verbose = Options.options.verbose
|
||||
Logs.init_log()
|
||||
|
||||
if Options.options.zones:
|
||||
Logs.zones = Options.options.zones.split(',')
|
||||
if not Logs.verbose:
|
||||
Logs.verbose = 1
|
||||
elif Logs.verbose > 0:
|
||||
Logs.zones = ['runner']
|
||||
|
||||
if Logs.verbose > 2:
|
||||
Logs.zones = ['*']
|
||||
|
||||
def run_command(cmd_name):
|
||||
"""
|
||||
Execute a single command. Called by :py:func:`waflib.Scripting.run_commands`.
|
||||
|
||||
:param cmd_name: command to execute, like ``build``
|
||||
:type cmd_name: string
|
||||
"""
|
||||
ctx = Context.create_context(cmd_name)
|
||||
ctx.log_timer = Utils.Timer()
|
||||
ctx.options = Options.options # provided for convenience
|
||||
ctx.cmd = cmd_name
|
||||
ctx.execute()
|
||||
return ctx
|
||||
|
||||
def run_commands():
|
||||
"""
|
||||
Execute the commands that were given on the command-line, and the other options
|
||||
Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization, and executed
|
||||
after :py:func:`waflib.Scripting.parse_options`.
|
||||
"""
|
||||
parse_options()
|
||||
run_command('init')
|
||||
while Options.commands:
|
||||
cmd_name = Options.commands.pop(0)
|
||||
ctx = run_command(cmd_name)
|
||||
Logs.info('%r finished successfully (%s)' % (cmd_name, str(ctx.log_timer)))
|
||||
run_command('shutdown')
|
||||
|
||||
###########################################################################################
|
||||
|
||||
def _can_distclean(name):
|
||||
# WARNING: this method may disappear anytime
|
||||
for k in '.o .moc .exe'.split():
|
||||
if name.endswith(k):
|
||||
return True
|
||||
return False
|
||||
|
||||
def distclean_dir(dirname):
|
||||
"""
|
||||
Distclean function called in the particular case when::
|
||||
|
||||
top == out
|
||||
|
||||
:param dirname: absolute path of the folder to clean
|
||||
:type dirname: string
|
||||
"""
|
||||
for (root, dirs, files) in os.walk(dirname):
|
||||
for f in files:
|
||||
if _can_distclean(f):
|
||||
fname = root + os.sep + f
|
||||
try:
|
||||
os.remove(fname)
|
||||
except OSError:
|
||||
Logs.warn('Could not remove %r' % fname)
|
||||
|
||||
for x in [Context.DBFILE, 'config.log']:
|
||||
try:
|
||||
os.remove(x)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
shutil.rmtree('c4che')
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def distclean(ctx):
|
||||
'''removes the build directory'''
|
||||
lst = os.listdir('.')
|
||||
for f in lst:
|
||||
if f == Options.lockfile:
|
||||
try:
|
||||
proj = ConfigSet.ConfigSet(f)
|
||||
except IOError:
|
||||
Logs.warn('Could not read %r' % f)
|
||||
continue
|
||||
|
||||
if proj['out_dir'] != proj['top_dir']:
|
||||
try:
|
||||
shutil.rmtree(proj['out_dir'])
|
||||
except IOError:
|
||||
pass
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
Logs.warn('project %r cannot be removed' % proj[Context.OUT])
|
||||
else:
|
||||
distclean_dir(proj['out_dir'])
|
||||
|
||||
for k in (proj['out_dir'], proj['top_dir'], proj['run_dir']):
|
||||
try:
|
||||
os.remove(os.path.join(k, Options.lockfile))
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
Logs.warn('file %r cannot be removed' % f)
|
||||
|
||||
# remove the local waf cache
|
||||
if f.startswith('.waf') and not Options.commands:
|
||||
shutil.rmtree(f, ignore_errors=True)
|
||||
|
||||
class Dist(Context.Context):
|
||||
'''creates an archive containing the project source code'''
|
||||
cmd = 'dist'
|
||||
fun = 'dist'
|
||||
algo = 'tar.bz2'
|
||||
ext_algo = {}
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
See :py:func:`waflib.Context.Context.execute`
|
||||
"""
|
||||
self.recurse([os.path.dirname(Context.g_module.root_path)])
|
||||
self.archive()
|
||||
|
||||
def archive(self):
|
||||
"""
|
||||
Create the archive.
|
||||
"""
|
||||
import tarfile
|
||||
|
||||
arch_name = self.get_arch_name()
|
||||
|
||||
try:
|
||||
self.base_path
|
||||
except AttributeError:
|
||||
self.base_path = self.path
|
||||
|
||||
node = self.base_path.make_node(arch_name)
|
||||
try:
|
||||
node.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
files = self.get_files()
|
||||
|
||||
if self.algo.startswith('tar.'):
|
||||
tar = tarfile.open(arch_name, 'w:' + self.algo.replace('tar.', ''))
|
||||
|
||||
for x in files:
|
||||
self.add_tar_file(x, tar)
|
||||
tar.close()
|
||||
elif self.algo == 'zip':
|
||||
import zipfile
|
||||
zip = zipfile.ZipFile(arch_name, 'w', compression=zipfile.ZIP_DEFLATED)
|
||||
|
||||
for x in files:
|
||||
archive_name = self.get_base_name() + '/' + x.path_from(self.base_path)
|
||||
zip.write(x.abspath(), archive_name, zipfile.ZIP_DEFLATED)
|
||||
zip.close()
|
||||
else:
|
||||
self.fatal('Valid algo types are tar.bz2, tar.gz or zip')
|
||||
|
||||
try:
|
||||
from hashlib import sha1 as sha
|
||||
except ImportError:
|
||||
from sha import sha
|
||||
try:
|
||||
digest = " (sha=%r)" % sha(node.read()).hexdigest()
|
||||
except Exception:
|
||||
digest = ''
|
||||
|
||||
Logs.info('New archive created: %s%s' % (self.arch_name, digest))
|
||||
|
||||
def get_tar_path(self, node):
|
||||
"""
|
||||
return the path to use for a node in the tar archive, the purpose of this
|
||||
is to let subclases resolve symbolic links or to change file names
|
||||
"""
|
||||
return node.abspath()
|
||||
|
||||
def add_tar_file(self, x, tar):
|
||||
"""
|
||||
Add a file to the tar archive. Transform symlinks into files if the files lie out of the project tree.
|
||||
"""
|
||||
p = self.get_tar_path(x)
|
||||
tinfo = tar.gettarinfo(name=p, arcname=self.get_tar_prefix() + '/' + x.path_from(self.base_path))
|
||||
tinfo.uid = 0
|
||||
tinfo.gid = 0
|
||||
tinfo.uname = 'root'
|
||||
tinfo.gname = 'root'
|
||||
|
||||
fu = None
|
||||
try:
|
||||
fu = open(p, 'rb')
|
||||
tar.addfile(tinfo, fileobj=fu)
|
||||
finally:
|
||||
if fu:
|
||||
fu.close()
|
||||
|
||||
def get_tar_prefix(self):
|
||||
try:
|
||||
return self.tar_prefix
|
||||
except AttributeError:
|
||||
return self.get_base_name()
|
||||
|
||||
def get_arch_name(self):
|
||||
"""
|
||||
Return the name of the archive to create. Change the default value by setting *arch_name*::
|
||||
|
||||
def dist(ctx):
|
||||
ctx.arch_name = 'ctx.tar.bz2'
|
||||
|
||||
:rtype: string
|
||||
"""
|
||||
try:
|
||||
self.arch_name
|
||||
except AttributeError:
|
||||
self.arch_name = self.get_base_name() + '.' + self.ext_algo.get(self.algo, self.algo)
|
||||
return self.arch_name
|
||||
|
||||
def get_base_name(self):
|
||||
"""
|
||||
Return the default name of the main directory in the archive, which is set to *appname-version*.
|
||||
Set the attribute *base_name* to change the default value::
|
||||
|
||||
def dist(ctx):
|
||||
ctx.base_name = 'files'
|
||||
|
||||
:rtype: string
|
||||
"""
|
||||
try:
|
||||
self.base_name
|
||||
except AttributeError:
|
||||
appname = getattr(Context.g_module, Context.APPNAME, 'noname')
|
||||
version = getattr(Context.g_module, Context.VERSION, '1.0')
|
||||
self.base_name = appname + '-' + version
|
||||
return self.base_name
|
||||
|
||||
def get_excl(self):
|
||||
"""
|
||||
Return the patterns to exclude for finding the files in the top-level directory. Set the attribute *excl*
|
||||
to change the default value::
|
||||
|
||||
def dist(ctx):
|
||||
ctx.excl = 'build **/*.o **/*.class'
|
||||
|
||||
:rtype: string
|
||||
"""
|
||||
try:
|
||||
return self.excl
|
||||
except AttributeError:
|
||||
self.excl = Node.exclude_regs + ' **/waf-1.7.* **/.waf-1.7* **/waf3-1.7.* **/.waf3-1.7* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*'
|
||||
nd = self.root.find_node(Context.out_dir)
|
||||
if nd:
|
||||
self.excl += ' ' + nd.path_from(self.base_path)
|
||||
return self.excl
|
||||
|
||||
def get_files(self):
|
||||
"""
|
||||
The files to package are searched automatically by :py:func:`waflib.Node.Node.ant_glob`. Set
|
||||
*files* to prevent this behaviour::
|
||||
|
||||
def dist(ctx):
|
||||
ctx.files = ctx.path.find_node('wscript')
|
||||
|
||||
The files are searched from the directory 'base_path', to change it, set::
|
||||
|
||||
def dist(ctx):
|
||||
ctx.base_path = path
|
||||
|
||||
:rtype: list of :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
try:
|
||||
files = self.files
|
||||
except AttributeError:
|
||||
files = self.base_path.ant_glob('**/*', excl=self.get_excl())
|
||||
return files
|
||||
|
||||
|
||||
def dist(ctx):
|
||||
'''makes a tarball for redistributing the sources'''
|
||||
pass
|
||||
|
||||
class DistCheck(Dist):
|
||||
"""
|
||||
Create an archive of the project, and try to build the project in a temporary directory::
|
||||
|
||||
$ waf distcheck
|
||||
"""
|
||||
|
||||
fun = 'distcheck'
|
||||
cmd = 'distcheck'
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
See :py:func:`waflib.Context.Context.execute`
|
||||
"""
|
||||
self.recurse([os.path.dirname(Context.g_module.root_path)])
|
||||
self.archive()
|
||||
self.check()
|
||||
|
||||
def check(self):
|
||||
"""
|
||||
Create the archive, uncompress it and try to build the project
|
||||
"""
|
||||
import tempfile, tarfile
|
||||
|
||||
t = None
|
||||
try:
|
||||
t = tarfile.open(self.get_arch_name())
|
||||
for x in t:
|
||||
t.extract(x)
|
||||
finally:
|
||||
if t:
|
||||
t.close()
|
||||
|
||||
cfg = []
|
||||
|
||||
if Options.options.distcheck_args:
|
||||
cfg = shlex.split(Options.options.distcheck_args)
|
||||
else:
|
||||
cfg = [x for x in sys.argv if x.startswith('-')]
|
||||
|
||||
instdir = tempfile.mkdtemp('.inst', self.get_base_name())
|
||||
ret = Utils.subprocess.Popen([sys.executable, sys.argv[0], 'configure', 'install', 'uninstall', '--destdir=' + instdir] + cfg, cwd=self.get_base_name()).wait()
|
||||
if ret:
|
||||
raise Errors.WafError('distcheck failed with code %i' % ret)
|
||||
|
||||
if os.path.exists(instdir):
|
||||
raise Errors.WafError('distcheck succeeded, but files were left in %s' % instdir)
|
||||
|
||||
shutil.rmtree(self.get_base_name())
|
||||
|
||||
|
||||
def distcheck(ctx):
|
||||
'''checks if the project compiles (tarball from 'dist')'''
|
||||
pass
|
||||
|
||||
def update(ctx):
|
||||
'''updates the plugins from the *waflib/extras* directory'''
|
||||
lst = Options.options.files.split(',')
|
||||
if not lst:
|
||||
lst = [x for x in Utils.listdir(Context.waf_dir + '/waflib/extras') if x.endswith('.py')]
|
||||
for x in lst:
|
||||
tool = x.replace('.py', '')
|
||||
try:
|
||||
Configure.download_tool(tool, force=True, ctx=ctx)
|
||||
except Errors.WafError:
|
||||
Logs.error('Could not find the tool %s in the remote repository' % x)
|
||||
|
||||
def autoconfigure(execute_method):
|
||||
"""
|
||||
Decorator used to set the commands that can be configured automatically
|
||||
"""
|
||||
def execute(self):
|
||||
if not Configure.autoconfig:
|
||||
return execute_method(self)
|
||||
|
||||
env = ConfigSet.ConfigSet()
|
||||
do_config = False
|
||||
try:
|
||||
env.load(os.path.join(Context.top_dir, Options.lockfile))
|
||||
except Exception:
|
||||
Logs.warn('Configuring the project')
|
||||
do_config = True
|
||||
else:
|
||||
if env.run_dir != Context.run_dir:
|
||||
do_config = True
|
||||
else:
|
||||
h = 0
|
||||
for f in env['files']:
|
||||
h = hash((h, Utils.readf(f, 'rb')))
|
||||
do_config = h != env.hash
|
||||
|
||||
if do_config:
|
||||
Options.commands.insert(0, self.cmd)
|
||||
Options.commands.insert(0, 'configure')
|
||||
return
|
||||
|
||||
return execute_method(self)
|
||||
return execute
|
||||
Build.BuildContext.execute = autoconfigure(Build.BuildContext.execute)
|
||||
|
||||
+1248
File diff suppressed because it is too large
Load Diff
+821
@@ -0,0 +1,821 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
Task generators
|
||||
|
||||
The class :py:class:`waflib.TaskGen.task_gen` encapsulates the creation of task objects (low-level code)
|
||||
The instances can have various parameters, but the creation of task nodes (Task.py)
|
||||
is always postponed. To achieve this, various methods are called from the method "apply"
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import copy, re, os
|
||||
from waflib import Task, Utils, Logs, Errors, ConfigSet, Node
|
||||
|
||||
feats = Utils.defaultdict(set)
|
||||
"""remember the methods declaring features"""
|
||||
|
||||
class task_gen(object):
|
||||
"""
|
||||
Instances of this class create :py:class:`waflib.Task.TaskBase` when
|
||||
calling the method :py:meth:`waflib.TaskGen.task_gen.post` from the main thread.
|
||||
A few notes:
|
||||
|
||||
* The methods to call (*self.meths*) can be specified dynamically (removing, adding, ..)
|
||||
* The 'features' are used to add methods to self.meths and then execute them
|
||||
* The attribute 'path' is a node representing the location of the task generator
|
||||
* The tasks created are added to the attribute *tasks*
|
||||
* The attribute 'idx' is a counter of task generators in the same path
|
||||
"""
|
||||
|
||||
mappings = {}
|
||||
prec = Utils.defaultdict(list)
|
||||
|
||||
def __init__(self, *k, **kw):
|
||||
"""
|
||||
The task generator objects predefine various attributes (source, target) for possible
|
||||
processing by process_rule (make-like rules) or process_source (extensions, misc methods)
|
||||
|
||||
The tasks are stored on the attribute 'tasks'. They are created by calling methods
|
||||
listed in self.meths *or* referenced in the attribute features
|
||||
A topological sort is performed to ease the method re-use.
|
||||
|
||||
The extra key/value elements passed in kw are set as attributes
|
||||
"""
|
||||
|
||||
# so we will have to play with directed acyclic graphs
|
||||
# detect cycles, etc
|
||||
self.source = ''
|
||||
self.target = ''
|
||||
|
||||
self.meths = []
|
||||
"""
|
||||
List of method names to execute (it is usually a good idea to avoid touching this)
|
||||
"""
|
||||
|
||||
self.prec = Utils.defaultdict(list)
|
||||
"""
|
||||
Precedence table for sorting the methods in self.meths
|
||||
"""
|
||||
|
||||
self.mappings = {}
|
||||
"""
|
||||
List of mappings {extension -> function} for processing files by extension
|
||||
"""
|
||||
|
||||
self.features = []
|
||||
"""
|
||||
List of feature names for bringing new methods in
|
||||
"""
|
||||
|
||||
self.tasks = []
|
||||
"""
|
||||
List of tasks created.
|
||||
"""
|
||||
|
||||
if not 'bld' in kw:
|
||||
# task generators without a build context :-/
|
||||
self.env = ConfigSet.ConfigSet()
|
||||
self.idx = 0
|
||||
self.path = None
|
||||
else:
|
||||
self.bld = kw['bld']
|
||||
self.env = self.bld.env.derive()
|
||||
self.path = self.bld.path # emulate chdir when reading scripts
|
||||
|
||||
# provide a unique id
|
||||
try:
|
||||
self.idx = self.bld.idx[id(self.path)] = self.bld.idx.get(id(self.path), 0) + 1
|
||||
except AttributeError:
|
||||
self.bld.idx = {}
|
||||
self.idx = self.bld.idx[id(self.path)] = 1
|
||||
|
||||
for key, val in kw.items():
|
||||
setattr(self, key, val)
|
||||
|
||||
def __str__(self):
|
||||
"""for debugging purposes"""
|
||||
return "<task_gen %r declared in %s>" % (self.name, self.path.abspath())
|
||||
|
||||
def __repr__(self):
|
||||
"""for debugging purposes"""
|
||||
lst = []
|
||||
for x in self.__dict__.keys():
|
||||
if x not in ['env', 'bld', 'compiled_tasks', 'tasks']:
|
||||
lst.append("%s=%s" % (x, repr(getattr(self, x))))
|
||||
return "bld(%s) in %s" % (", ".join(lst), self.path.abspath())
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
If not set, the name is computed from the target name::
|
||||
|
||||
def build(bld):
|
||||
x = bld(name='foo')
|
||||
x.get_name() # foo
|
||||
y = bld(target='bar')
|
||||
y.get_name() # bar
|
||||
|
||||
:rtype: string
|
||||
:return: name of this task generator
|
||||
"""
|
||||
try:
|
||||
return self._name
|
||||
except AttributeError:
|
||||
if isinstance(self.target, list):
|
||||
lst = [str(x) for x in self.target]
|
||||
name = self._name = ','.join(lst)
|
||||
else:
|
||||
name = self._name = str(self.target)
|
||||
return name
|
||||
def set_name(self, name):
|
||||
self._name = name
|
||||
|
||||
name = property(get_name, set_name)
|
||||
|
||||
def to_list(self, val):
|
||||
"""
|
||||
Ensure that a parameter is a list
|
||||
|
||||
:type val: string or list of string
|
||||
:param val: input to return as a list
|
||||
:rtype: list
|
||||
"""
|
||||
if isinstance(val, str): return val.split()
|
||||
else: return val
|
||||
|
||||
def post(self):
|
||||
"""
|
||||
Create task objects. The following operations are performed:
|
||||
|
||||
#. The body of this method is called only once and sets the attribute ``posted``
|
||||
#. The attribute ``features`` is used to add more methods in ``self.meths``
|
||||
#. The methods are sorted by the precedence table ``self.prec`` or `:waflib:attr:waflib.TaskGen.task_gen.prec`
|
||||
#. The methods are then executed in order
|
||||
#. The tasks created are added to :py:attr:`waflib.TaskGen.task_gen.tasks`
|
||||
"""
|
||||
|
||||
# we could add a decorator to let the task run once, but then python 2.3 will be difficult to support
|
||||
if getattr(self, 'posted', None):
|
||||
#error("OBJECT ALREADY POSTED" + str( self))
|
||||
return False
|
||||
self.posted = True
|
||||
|
||||
keys = set(self.meths)
|
||||
|
||||
# add the methods listed in the features
|
||||
self.features = Utils.to_list(self.features)
|
||||
for x in self.features + ['*']:
|
||||
st = feats[x]
|
||||
if not st:
|
||||
if not x in Task.classes:
|
||||
Logs.warn('feature %r does not exist - bind at least one method to it' % x)
|
||||
keys.update(list(st)) # ironpython 2.7 wants the cast to list
|
||||
|
||||
# copy the precedence table
|
||||
prec = {}
|
||||
prec_tbl = self.prec or task_gen.prec
|
||||
for x in prec_tbl:
|
||||
if x in keys:
|
||||
prec[x] = prec_tbl[x]
|
||||
|
||||
# elements disconnected
|
||||
tmp = []
|
||||
for a in keys:
|
||||
for x in prec.values():
|
||||
if a in x: break
|
||||
else:
|
||||
tmp.append(a)
|
||||
|
||||
tmp.sort()
|
||||
|
||||
# topological sort
|
||||
out = []
|
||||
while tmp:
|
||||
e = tmp.pop()
|
||||
if e in keys: out.append(e)
|
||||
try:
|
||||
nlst = prec[e]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
del prec[e]
|
||||
for x in nlst:
|
||||
for y in prec:
|
||||
if x in prec[y]:
|
||||
break
|
||||
else:
|
||||
tmp.append(x)
|
||||
|
||||
if prec:
|
||||
raise Errors.WafError('Cycle detected in the method execution %r' % prec)
|
||||
out.reverse()
|
||||
self.meths = out
|
||||
|
||||
# then we run the methods in order
|
||||
Logs.debug('task_gen: posting %s %d' % (self, id(self)))
|
||||
for x in out:
|
||||
try:
|
||||
v = getattr(self, x)
|
||||
except AttributeError:
|
||||
raise Errors.WafError('%r is not a valid task generator method' % x)
|
||||
Logs.debug('task_gen: -> %s (%d)' % (x, id(self)))
|
||||
v()
|
||||
|
||||
Logs.debug('task_gen: posted %s' % self.name)
|
||||
return True
|
||||
|
||||
def get_hook(self, node):
|
||||
"""
|
||||
:param node: Input file to process
|
||||
:type node: :py:class:`waflib.Tools.Node.Node`
|
||||
:return: A method able to process the input node by looking at the extension
|
||||
:rtype: function
|
||||
"""
|
||||
name = node.name
|
||||
for k in self.mappings:
|
||||
if name.endswith(k):
|
||||
return self.mappings[k]
|
||||
for k in task_gen.mappings:
|
||||
if name.endswith(k):
|
||||
return task_gen.mappings[k]
|
||||
raise Errors.WafError("File %r has no mapping in %r (did you forget to load a waf tool?)" % (node, task_gen.mappings.keys()))
|
||||
|
||||
def create_task(self, name, src=None, tgt=None):
|
||||
"""
|
||||
Wrapper for creating task instances. The classes are retrieved from the
|
||||
context class if possible, then from the global dict Task.classes.
|
||||
|
||||
:param name: task class name
|
||||
:type name: string
|
||||
:param src: input nodes
|
||||
:type src: list of :py:class:`waflib.Tools.Node.Node`
|
||||
:param tgt: output nodes
|
||||
:type tgt: list of :py:class:`waflib.Tools.Node.Node`
|
||||
:return: A task object
|
||||
:rtype: :py:class:`waflib.Task.TaskBase`
|
||||
"""
|
||||
task = Task.classes[name](env=self.env.derive(), generator=self)
|
||||
if src:
|
||||
task.set_inputs(src)
|
||||
if tgt:
|
||||
task.set_outputs(tgt)
|
||||
self.tasks.append(task)
|
||||
return task
|
||||
|
||||
def clone(self, env):
|
||||
"""
|
||||
Make a copy of a task generator. Once the copy is made, it is necessary to ensure that the
|
||||
it does not create the same output files as the original, or the same files may
|
||||
be compiled several times.
|
||||
|
||||
:param env: A configuration set
|
||||
:type env: :py:class:`waflib.ConfigSet.ConfigSet`
|
||||
:return: A copy
|
||||
:rtype: :py:class:`waflib.TaskGen.task_gen`
|
||||
"""
|
||||
newobj = self.bld()
|
||||
for x in self.__dict__:
|
||||
if x in ['env', 'bld']:
|
||||
continue
|
||||
elif x in ['path', 'features']:
|
||||
setattr(newobj, x, getattr(self, x))
|
||||
else:
|
||||
setattr(newobj, x, copy.copy(getattr(self, x)))
|
||||
|
||||
newobj.posted = False
|
||||
if isinstance(env, str):
|
||||
newobj.env = self.bld.all_envs[env].derive()
|
||||
else:
|
||||
newobj.env = env.derive()
|
||||
|
||||
return newobj
|
||||
|
||||
def declare_chain(name='', rule=None, reentrant=None, color='BLUE',
|
||||
ext_in=[], ext_out=[], before=[], after=[], decider=None, scan=None, install_path=None, shell=False):
|
||||
"""
|
||||
Create a new mapping and a task class for processing files by extension.
|
||||
See Tools/flex.py for an example.
|
||||
|
||||
:param name: name for the task class
|
||||
:type name: string
|
||||
:param rule: function to execute or string to be compiled in a function
|
||||
:type rule: string or function
|
||||
:param reentrant: re-inject the output file in the process (done automatically, set to 0 to disable)
|
||||
:type reentrant: int
|
||||
:param color: color for the task output
|
||||
:type color: string
|
||||
:param ext_in: execute the task only after the files of such extensions are created
|
||||
:type ext_in: list of string
|
||||
:param ext_out: execute the task only before files of such extensions are processed
|
||||
:type ext_out: list of string
|
||||
:param before: execute instances of this task before classes of the given names
|
||||
:type before: list of string
|
||||
:param after: execute instances of this task after classes of the given names
|
||||
:type after: list of string
|
||||
:param decider: if present, use it to create the output nodes for the task
|
||||
:type decider: function
|
||||
:param scan: scanner function for the task
|
||||
:type scan: function
|
||||
:param install_path: installation path for the output nodes
|
||||
:type install_path: string
|
||||
"""
|
||||
ext_in = Utils.to_list(ext_in)
|
||||
ext_out = Utils.to_list(ext_out)
|
||||
if not name:
|
||||
name = rule
|
||||
cls = Task.task_factory(name, rule, color=color, ext_in=ext_in, ext_out=ext_out, before=before, after=after, scan=scan, shell=shell)
|
||||
|
||||
def x_file(self, node):
|
||||
ext = decider and decider(self, node) or cls.ext_out
|
||||
if ext_in:
|
||||
_ext_in = ext_in[0]
|
||||
|
||||
tsk = self.create_task(name, node)
|
||||
cnt = 0
|
||||
|
||||
keys = list(self.mappings.keys()) + list(self.__class__.mappings.keys())
|
||||
for x in ext:
|
||||
k = node.change_ext(x, ext_in=_ext_in)
|
||||
tsk.outputs.append(k)
|
||||
|
||||
if reentrant != None:
|
||||
if cnt < int(reentrant):
|
||||
self.source.append(k)
|
||||
else:
|
||||
for y in keys: # ~ nfile * nextensions :-/
|
||||
if k.name.endswith(y):
|
||||
self.source.append(k)
|
||||
break
|
||||
cnt += 1
|
||||
|
||||
if install_path:
|
||||
self.bld.install_files(install_path, tsk.outputs)
|
||||
return tsk
|
||||
|
||||
for x in cls.ext_in:
|
||||
task_gen.mappings[x] = x_file
|
||||
return x_file
|
||||
|
||||
def taskgen_method(func):
|
||||
"""
|
||||
Decorator: register a method as a task generator method.
|
||||
The function must accept a task generator as first parameter::
|
||||
|
||||
from waflib.TaskGen import taskgen_method
|
||||
@taskgen_method
|
||||
def mymethod(self):
|
||||
pass
|
||||
|
||||
:param func: task generator method to add
|
||||
:type func: function
|
||||
:rtype: function
|
||||
"""
|
||||
setattr(task_gen, func.__name__, func)
|
||||
return func
|
||||
|
||||
def feature(*k):
|
||||
"""
|
||||
Decorator: register a task generator method that will be executed when the
|
||||
object attribute 'feature' contains the corresponding key(s)::
|
||||
|
||||
from waflib.Task import feature
|
||||
@feature('myfeature')
|
||||
def myfunction(self):
|
||||
print('that is my feature!')
|
||||
def build(bld):
|
||||
bld(features='myfeature')
|
||||
|
||||
:param k: feature names
|
||||
:type k: list of string
|
||||
"""
|
||||
def deco(func):
|
||||
setattr(task_gen, func.__name__, func)
|
||||
for name in k:
|
||||
feats[name].update([func.__name__])
|
||||
return func
|
||||
return deco
|
||||
|
||||
def before_method(*k):
|
||||
"""
|
||||
Decorator: register a task generator method which will be executed
|
||||
before the functions of given name(s)::
|
||||
|
||||
from waflib.TaskGen import feature, before
|
||||
@feature('myfeature')
|
||||
@before_method('fun2')
|
||||
def fun1(self):
|
||||
print('feature 1!')
|
||||
@feature('myfeature')
|
||||
def fun2(self):
|
||||
print('feature 2!')
|
||||
def build(bld):
|
||||
bld(features='myfeature')
|
||||
|
||||
:param k: method names
|
||||
:type k: list of string
|
||||
"""
|
||||
def deco(func):
|
||||
setattr(task_gen, func.__name__, func)
|
||||
for fun_name in k:
|
||||
if not func.__name__ in task_gen.prec[fun_name]:
|
||||
task_gen.prec[fun_name].append(func.__name__)
|
||||
#task_gen.prec[fun_name].sort()
|
||||
return func
|
||||
return deco
|
||||
before = before_method
|
||||
|
||||
def after_method(*k):
|
||||
"""
|
||||
Decorator: register a task generator method which will be executed
|
||||
after the functions of given name(s)::
|
||||
|
||||
from waflib.TaskGen import feature, after
|
||||
@feature('myfeature')
|
||||
@after_method('fun2')
|
||||
def fun1(self):
|
||||
print('feature 1!')
|
||||
@feature('myfeature')
|
||||
def fun2(self):
|
||||
print('feature 2!')
|
||||
def build(bld):
|
||||
bld(features='myfeature')
|
||||
|
||||
:param k: method names
|
||||
:type k: list of string
|
||||
"""
|
||||
def deco(func):
|
||||
setattr(task_gen, func.__name__, func)
|
||||
for fun_name in k:
|
||||
if not fun_name in task_gen.prec[func.__name__]:
|
||||
task_gen.prec[func.__name__].append(fun_name)
|
||||
#task_gen.prec[func.__name__].sort()
|
||||
return func
|
||||
return deco
|
||||
after = after_method
|
||||
|
||||
def extension(*k):
|
||||
"""
|
||||
Decorator: register a task generator method which will be invoked during
|
||||
the processing of source files for the extension given::
|
||||
|
||||
from waflib import Task
|
||||
class mytask(Task):
|
||||
run_str = 'cp ${SRC} ${TGT}'
|
||||
@extension('.moo')
|
||||
def create_maa_file(self, node):
|
||||
self.create_task('mytask', node, node.change_ext('.maa'))
|
||||
def build(bld):
|
||||
bld(source='foo.moo')
|
||||
"""
|
||||
def deco(func):
|
||||
setattr(task_gen, func.__name__, func)
|
||||
for x in k:
|
||||
task_gen.mappings[x] = func
|
||||
return func
|
||||
return deco
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# The following methods are task generator methods commonly used
|
||||
# they are almost examples, the rest of waf core does not depend on them
|
||||
|
||||
@taskgen_method
|
||||
def to_nodes(self, lst, path=None):
|
||||
"""
|
||||
Convert the input list into a list of nodes.
|
||||
It is used by :py:func:`waflib.TaskGen.process_source` and :py:func:`waflib.TaskGen.process_rule`.
|
||||
It is designed for source files, for folders, see :py:func:`waflib.Tools.ccroot.to_incnodes`:
|
||||
|
||||
:param lst: input list
|
||||
:type lst: list of string and nodes
|
||||
:param path: path from which to search the nodes (by default, :py:attr:`waflib.TaskGen.task_gen.path`)
|
||||
:type path: :py:class:`waflib.Tools.Node.Node`
|
||||
:rtype: list of :py:class:`waflib.Tools.Node.Node`
|
||||
"""
|
||||
tmp = []
|
||||
path = path or self.path
|
||||
find = path.find_resource
|
||||
|
||||
if isinstance(lst, self.path.__class__):
|
||||
lst = [lst]
|
||||
|
||||
# either a list or a string, convert to a list of nodes
|
||||
for x in Utils.to_list(lst):
|
||||
if isinstance(x, str):
|
||||
node = find(x)
|
||||
else:
|
||||
node = x
|
||||
if not node:
|
||||
raise Errors.WafError("source not found: %r in %r" % (x, self))
|
||||
tmp.append(node)
|
||||
return tmp
|
||||
|
||||
@feature('*')
|
||||
def process_source(self):
|
||||
"""
|
||||
Process each element in the attribute ``source`` by extension.
|
||||
|
||||
#. The *source* list is converted through :py:meth:`waflib.TaskGen.to_nodes` to a list of :py:class:`waflib.Node.Node` first.
|
||||
#. File extensions are mapped to methods having the signature: ``def meth(self, node)`` by :py:meth:`waflib.TaskGen.extension`
|
||||
#. The method is retrieved through :py:meth:`waflib.TaskGen.task_gen.get_hook`
|
||||
#. When called, the methods may modify self.source to append more source to process
|
||||
#. The mappings can map an extension or a filename (see the code below)
|
||||
"""
|
||||
self.source = self.to_nodes(getattr(self, 'source', []))
|
||||
for node in self.source:
|
||||
self.get_hook(node)(self, node)
|
||||
|
||||
@feature('*')
|
||||
@before_method('process_source')
|
||||
def process_rule(self):
|
||||
"""
|
||||
Process the attribute ``rule``. When present, :py:meth:`waflib.TaskGen.process_source` is disabled::
|
||||
|
||||
def build(bld):
|
||||
bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt')
|
||||
"""
|
||||
if not getattr(self, 'rule', None):
|
||||
return
|
||||
|
||||
# create the task class
|
||||
name = str(getattr(self, 'name', None) or self.target or getattr(self.rule, '__name__', self.rule))
|
||||
|
||||
# or we can put the class in a cache for performance reasons
|
||||
try:
|
||||
cache = self.bld.cache_rule_attr
|
||||
except AttributeError:
|
||||
cache = self.bld.cache_rule_attr = {}
|
||||
|
||||
cls = None
|
||||
if getattr(self, 'cache_rule', 'True'):
|
||||
try:
|
||||
cls = cache[(name, self.rule)]
|
||||
except KeyError:
|
||||
pass
|
||||
if not cls:
|
||||
cls = Task.task_factory(name, self.rule,
|
||||
getattr(self, 'vars', []),
|
||||
shell=getattr(self, 'shell', True), color=getattr(self, 'color', 'BLUE'),
|
||||
scan = getattr(self, 'scan', None))
|
||||
if getattr(self, 'scan', None):
|
||||
cls.scan = self.scan
|
||||
elif getattr(self, 'deps', None):
|
||||
def scan(self):
|
||||
nodes = []
|
||||
for x in self.generator.to_list(getattr(self.generator, 'deps', None)):
|
||||
node = self.generator.path.find_resource(x)
|
||||
if not node:
|
||||
self.generator.bld.fatal('Could not find %r (was it declared?)' % x)
|
||||
nodes.append(node)
|
||||
return [nodes, []]
|
||||
cls.scan = scan
|
||||
|
||||
if getattr(self, 'update_outputs', None):
|
||||
Task.update_outputs(cls)
|
||||
|
||||
if getattr(self, 'always', None):
|
||||
Task.always_run(cls)
|
||||
|
||||
for x in ['after', 'before', 'ext_in', 'ext_out']:
|
||||
setattr(cls, x, getattr(self, x, []))
|
||||
|
||||
if getattr(self, 'cache_rule', 'True'):
|
||||
cache[(name, self.rule)] = cls
|
||||
|
||||
# now create one instance
|
||||
tsk = self.create_task(name)
|
||||
|
||||
if getattr(self, 'target', None):
|
||||
if isinstance(self.target, str):
|
||||
self.target = self.target.split()
|
||||
if not isinstance(self.target, list):
|
||||
self.target = [self.target]
|
||||
for x in self.target:
|
||||
if isinstance(x, str):
|
||||
tsk.outputs.append(self.path.find_or_declare(x))
|
||||
else:
|
||||
x.parent.mkdir() # if a node was given, create the required folders
|
||||
tsk.outputs.append(x)
|
||||
if getattr(self, 'install_path', None):
|
||||
# from waf 1.5
|
||||
# although convenient, it does not 1. allow to name the target file and 2. symlinks
|
||||
# TODO remove in waf 1.7
|
||||
self.bld.install_files(self.install_path, tsk.outputs)
|
||||
|
||||
if getattr(self, 'source', None):
|
||||
tsk.inputs = self.to_nodes(self.source)
|
||||
# bypass the execution of process_source by setting the source to an empty list
|
||||
self.source = []
|
||||
|
||||
if getattr(self, 'cwd', None):
|
||||
tsk.cwd = self.cwd
|
||||
|
||||
@feature('seq')
|
||||
def sequence_order(self):
|
||||
"""
|
||||
Add a strict sequential constraint between the tasks generated by task generators.
|
||||
It works because task generators are posted in order.
|
||||
It will not post objects which belong to other folders.
|
||||
|
||||
Example::
|
||||
|
||||
bld(features='javac seq')
|
||||
bld(features='jar seq')
|
||||
|
||||
To start a new sequence, set the attribute seq_start, for example::
|
||||
|
||||
obj = bld(features='seq')
|
||||
obj.seq_start = True
|
||||
|
||||
Note that the method is executed in last position. This is more an
|
||||
example than a widely-used solution.
|
||||
"""
|
||||
if self.meths and self.meths[-1] != 'sequence_order':
|
||||
self.meths.append('sequence_order')
|
||||
return
|
||||
|
||||
if getattr(self, 'seq_start', None):
|
||||
return
|
||||
|
||||
# all the tasks previously declared must be run before these
|
||||
if getattr(self.bld, 'prev', None):
|
||||
self.bld.prev.post()
|
||||
for x in self.bld.prev.tasks:
|
||||
for y in self.tasks:
|
||||
y.set_run_after(x)
|
||||
|
||||
self.bld.prev = self
|
||||
|
||||
|
||||
re_m4 = re.compile('@(\w+)@', re.M)
|
||||
|
||||
class subst_pc(Task.Task):
|
||||
"""
|
||||
Create *.pc* files from *.pc.in*. The task is executed whenever an input variable used
|
||||
in the substitution changes.
|
||||
"""
|
||||
|
||||
def run(self):
|
||||
"Substitutes variables in a .in file"
|
||||
|
||||
if getattr(self.generator, 'is_copy', None):
|
||||
self.outputs[0].write(self.inputs[0].read('rb'), 'wb')
|
||||
if getattr(self.generator, 'chmod', None):
|
||||
os.chmod(self.outputs[0].abspath(), self.generator.chmod)
|
||||
return None
|
||||
|
||||
if getattr(self.generator, 'fun', None):
|
||||
self.generator.fun(self)
|
||||
|
||||
code = self.inputs[0].read(encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))
|
||||
if getattr(self.generator, 'subst_fun', None):
|
||||
code = self.generator.subst_fun(self, code)
|
||||
if code:
|
||||
self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))
|
||||
return
|
||||
|
||||
# replace all % by %% to prevent errors by % signs
|
||||
code = code.replace('%', '%%')
|
||||
|
||||
# extract the vars foo into lst and replace @foo@ by %(foo)s
|
||||
lst = []
|
||||
def repl(match):
|
||||
g = match.group
|
||||
if g(1):
|
||||
lst.append(g(1))
|
||||
return "%%(%s)s" % g(1)
|
||||
return ''
|
||||
code = re_m4.sub(repl, code)
|
||||
|
||||
try:
|
||||
d = self.generator.dct
|
||||
except AttributeError:
|
||||
d = {}
|
||||
for x in lst:
|
||||
tmp = getattr(self.generator, x, '') or self.env.get_flat(x) or self.env.get_flat(x.upper())
|
||||
d[x] = str(tmp)
|
||||
|
||||
code = code % d
|
||||
self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))
|
||||
self.generator.bld.raw_deps[self.uid()] = self.dep_vars = lst
|
||||
|
||||
# make sure the signature is updated
|
||||
try: delattr(self, 'cache_sig')
|
||||
except AttributeError: pass
|
||||
|
||||
if getattr(self.generator, 'chmod', None):
|
||||
os.chmod(self.outputs[0].abspath(), self.generator.chmod)
|
||||
|
||||
def sig_vars(self):
|
||||
"""
|
||||
Compute a hash (signature) of the variables used in the substitution
|
||||
"""
|
||||
bld = self.generator.bld
|
||||
env = self.env
|
||||
upd = self.m.update
|
||||
|
||||
if getattr(self.generator, 'fun', None):
|
||||
upd(Utils.h_fun(self.generator.fun).encode())
|
||||
if getattr(self.generator, 'subst_fun', None):
|
||||
upd(Utils.h_fun(self.generator.subst_fun).encode())
|
||||
|
||||
# raw_deps: persistent custom values returned by the scanner
|
||||
vars = self.generator.bld.raw_deps.get(self.uid(), [])
|
||||
|
||||
# hash both env vars and task generator attributes
|
||||
act_sig = bld.hash_env_vars(env, vars)
|
||||
upd(act_sig)
|
||||
|
||||
lst = [getattr(self.generator, x, '') for x in vars]
|
||||
upd(Utils.h_list(lst))
|
||||
|
||||
return self.m.digest()
|
||||
|
||||
@extension('.pc.in')
|
||||
def add_pcfile(self, node):
|
||||
"""
|
||||
Process *.pc.in* files to *.pc*. Install the results to ``${PREFIX}/lib/pkgconfig/``
|
||||
|
||||
def build(bld):
|
||||
bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/')
|
||||
"""
|
||||
tsk = self.create_task('subst_pc', node, node.change_ext('.pc', '.pc.in'))
|
||||
self.bld.install_files(getattr(self, 'install_path', '${LIBDIR}/pkgconfig/'), tsk.outputs)
|
||||
|
||||
class subst(subst_pc):
|
||||
pass
|
||||
|
||||
@feature('subst')
|
||||
@before_method('process_source', 'process_rule')
|
||||
def process_subst(self):
|
||||
"""
|
||||
Define a transformation that substitutes the contents of *source* files to *target* files::
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features='subst',
|
||||
source='foo.c.in',
|
||||
target='foo.c',
|
||||
install_path='${LIBDIR}/pkgconfig',
|
||||
VAR = 'val'
|
||||
)
|
||||
|
||||
The input files are supposed to contain macros of the form *@VAR@*, where *VAR* is an argument
|
||||
of the task generator object.
|
||||
|
||||
This method overrides the processing by :py:meth:`waflib.TaskGen.process_source`.
|
||||
"""
|
||||
|
||||
src = Utils.to_list(getattr(self, 'source', []))
|
||||
if isinstance(src, Node.Node):
|
||||
src = [src]
|
||||
tgt = Utils.to_list(getattr(self, 'target', []))
|
||||
if isinstance(tgt, Node.Node):
|
||||
tgt = [tgt]
|
||||
if len(src) != len(tgt):
|
||||
raise Errors.WafError('invalid number of source/target for %r' % self)
|
||||
|
||||
for x, y in zip(src, tgt):
|
||||
if not x or not y:
|
||||
raise Errors.WafError('null source or target for %r' % self)
|
||||
a, b = None, None
|
||||
|
||||
if isinstance(x, str) and isinstance(y, str) and x == y:
|
||||
a = self.path.find_node(x)
|
||||
b = self.path.get_bld().make_node(y)
|
||||
if not os.path.isfile(b.abspath()):
|
||||
b.sig = None
|
||||
b.parent.mkdir()
|
||||
else:
|
||||
if isinstance(x, str):
|
||||
a = self.path.find_resource(x)
|
||||
elif isinstance(x, Node.Node):
|
||||
a = x
|
||||
if isinstance(y, str):
|
||||
b = self.path.find_or_declare(y)
|
||||
elif isinstance(y, Node.Node):
|
||||
b = y
|
||||
|
||||
if not a:
|
||||
raise Errors.WafError('cound not find %r for %r' % (x, self))
|
||||
|
||||
has_constraints = False
|
||||
tsk = self.create_task('subst', a, b)
|
||||
for k in ('after', 'before', 'ext_in', 'ext_out'):
|
||||
val = getattr(self, k, None)
|
||||
if val:
|
||||
has_constraints = True
|
||||
setattr(tsk, k, val)
|
||||
|
||||
# paranoid safety measure for the general case foo.in->foo.h with ambiguous dependencies
|
||||
if not has_constraints and b.name.endswith('.h'):
|
||||
tsk.before = [k for k in ('c', 'cxx') if k in Task.classes]
|
||||
|
||||
inst_to = getattr(self, 'install_path', None)
|
||||
if inst_to:
|
||||
self.bld.install_files(inst_to, b, chmod=getattr(self, 'chmod', Utils.O644))
|
||||
|
||||
self.source = []
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
|
||||
"""
|
||||
The **ar** program creates static libraries. This tool is almost always loaded
|
||||
from others (C, C++, D, etc) for static library support.
|
||||
"""
|
||||
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_ar(conf):
|
||||
"""Configuration helper used by C/C++ tools to enable the support for static libraries"""
|
||||
conf.load('ar')
|
||||
|
||||
def configure(conf):
|
||||
"""Find the ar program and set the default flags in ``conf.env.ARFLAGS``"""
|
||||
conf.find_program('ar', var='AR')
|
||||
conf.env.ARFLAGS = 'rcs'
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2008-2010 (ita)
|
||||
|
||||
"""
|
||||
Assembly support, used by tools such as gas and nasm
|
||||
|
||||
To declare targets using assembly::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('gcc gas')
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features='c cstlib asm',
|
||||
source = 'test.S',
|
||||
target = 'asmtest')
|
||||
|
||||
bld(
|
||||
features='asm asmprogram',
|
||||
source = 'test.S',
|
||||
target = 'asmtest')
|
||||
|
||||
Support for pure asm programs and libraries should also work::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('nasm')
|
||||
conf.find_program('ld', 'ASLINK')
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features='asm asmprogram',
|
||||
source = 'test.S',
|
||||
target = 'asmtest')
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib import Task, Utils
|
||||
import waflib.Task
|
||||
from waflib.Tools.ccroot import link_task, stlink_task
|
||||
from waflib.TaskGen import extension, feature
|
||||
|
||||
class asm(Task.Task):
|
||||
"""
|
||||
Compile asm files by gas/nasm/yasm/...
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}'
|
||||
|
||||
@extension('.s', '.S', '.asm', '.ASM', '.spp', '.SPP')
|
||||
def asm_hook(self, node):
|
||||
"""
|
||||
Bind the asm extension to the asm task
|
||||
|
||||
:param node: input file
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
return self.create_compiled_task('asm', node)
|
||||
|
||||
class asmprogram(link_task):
|
||||
"Link object files into a c program"
|
||||
run_str = '${ASLINK} ${ASLINKFLAGS} ${ASLNK_TGT_F}${TGT} ${ASLNK_SRC_F}${SRC}'
|
||||
ext_out = ['.bin']
|
||||
inst_to = '${BINDIR}'
|
||||
|
||||
class asmshlib(asmprogram):
|
||||
"Link object files into a c shared library"
|
||||
inst_to = '${LIBDIR}'
|
||||
|
||||
class asmstlib(stlink_task):
|
||||
"Link object files into a c static library"
|
||||
pass # do not remove
|
||||
|
||||
def configure(conf):
|
||||
conf.env['ASMPATH_ST'] = '-I%s'
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# John O'Meara, 2006
|
||||
# Thomas Nagy 2009-2010 (ita)
|
||||
|
||||
"""
|
||||
The **bison** program is a code generator which creates C or C++ files.
|
||||
The generated files are compiled into object files.
|
||||
"""
|
||||
|
||||
from waflib import Task
|
||||
from waflib.TaskGen import extension
|
||||
|
||||
class bison(Task.Task):
|
||||
"""Compile bison files"""
|
||||
color = 'BLUE'
|
||||
run_str = '${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}'
|
||||
ext_out = ['.h'] # just to make sure
|
||||
|
||||
@extension('.y', '.yc', '.yy')
|
||||
def big_bison(self, node):
|
||||
"""
|
||||
Create a bison task, which must be executed from the directory of the output file.
|
||||
"""
|
||||
has_h = '-d' in self.env['BISONFLAGS']
|
||||
|
||||
outs = []
|
||||
if node.name.endswith('.yc'):
|
||||
outs.append(node.change_ext('.tab.cc'))
|
||||
if has_h:
|
||||
outs.append(node.change_ext('.tab.hh'))
|
||||
else:
|
||||
outs.append(node.change_ext('.tab.c'))
|
||||
if has_h:
|
||||
outs.append(node.change_ext('.tab.h'))
|
||||
|
||||
tsk = self.create_task('bison', node, outs)
|
||||
tsk.cwd = node.parent.get_bld().abspath()
|
||||
|
||||
# and the c/cxx file must be compiled too
|
||||
self.source.append(outs[0])
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the *bison* program
|
||||
"""
|
||||
conf.find_program('bison', var='BISON')
|
||||
conf.env.BISONFLAGS = ['-d']
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"Base for c programs/libraries"
|
||||
|
||||
from waflib import TaskGen, Task, Utils
|
||||
from waflib.Tools import c_preproc
|
||||
from waflib.Tools.ccroot import link_task, stlink_task
|
||||
|
||||
@TaskGen.extension('.c')
|
||||
def c_hook(self, node):
|
||||
"Bind the c file extension to the creation of a :py:class:`waflib.Tools.c.c` instance"
|
||||
return self.create_compiled_task('c', node)
|
||||
|
||||
class c(Task.Task):
|
||||
"Compile C files into object files"
|
||||
run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT}'
|
||||
vars = ['CCDEPS'] # unused variable to depend on, just in case
|
||||
ext_in = ['.h'] # set the build order easily by using ext_out=['.h']
|
||||
scan = c_preproc.scan
|
||||
|
||||
class cprogram(link_task):
|
||||
"Link object files into a c program"
|
||||
run_str = '${LINK_CC} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'
|
||||
ext_out = ['.bin']
|
||||
vars = ['LINKDEPS']
|
||||
inst_to = '${BINDIR}'
|
||||
|
||||
class cshlib(cprogram):
|
||||
"Link object files into a c shared library"
|
||||
inst_to = '${LIBDIR}'
|
||||
|
||||
class cstlib(stlink_task):
|
||||
"Link object files into a c static library"
|
||||
pass # do not remove
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"base for all c/c++ programs and libraries"
|
||||
|
||||
import os, sys, re
|
||||
from waflib import Utils, Build
|
||||
from waflib.Configure import conf
|
||||
|
||||
def get_extensions(lst):
|
||||
"""
|
||||
:param lst: files to process
|
||||
:list lst: list of string or :py:class:`waflib.Node.Node`
|
||||
:return: list of file extensions
|
||||
:rtype: list of string
|
||||
"""
|
||||
ret = []
|
||||
for x in Utils.to_list(lst):
|
||||
try:
|
||||
if not isinstance(x, str):
|
||||
x = x.name
|
||||
ret.append(x[x.rfind('.') + 1:])
|
||||
except Exception:
|
||||
pass
|
||||
return ret
|
||||
|
||||
def sniff_features(**kw):
|
||||
"""
|
||||
Look at the source files and return the features for a task generator (mainly cc and cxx)::
|
||||
|
||||
snif_features(source=['foo.c', 'foo.cxx'], type='shlib')
|
||||
# returns ['cxx', 'c', 'cxxshlib', 'cshlib']
|
||||
|
||||
:param source: source files to process
|
||||
:type source: list of string or :py:class:`waflib.Node.Node`
|
||||
:param type: object type in *program*, *shlib* or *stlib*
|
||||
:type type: string
|
||||
:return: the list of features for a task generator processing the source files
|
||||
:rtype: list of string
|
||||
"""
|
||||
exts = get_extensions(kw['source'])
|
||||
type = kw['_type']
|
||||
feats = []
|
||||
|
||||
# watch the order, cxx will have the precedence
|
||||
if 'cxx' in exts or 'cpp' in exts or 'c++' in exts or 'cc' in exts or 'C' in exts:
|
||||
feats.append('cxx')
|
||||
|
||||
if 'c' in exts or 'vala' in exts:
|
||||
feats.append('c')
|
||||
|
||||
if 'd' in exts:
|
||||
feats.append('d')
|
||||
|
||||
if 'java' in exts:
|
||||
feats.append('java')
|
||||
|
||||
if 'java' in exts:
|
||||
return 'java'
|
||||
|
||||
if type in ['program', 'shlib', 'stlib']:
|
||||
for x in feats:
|
||||
if x in ['cxx', 'd', 'c']:
|
||||
feats.append(x + type)
|
||||
|
||||
return feats
|
||||
|
||||
def set_features(kw, _type):
|
||||
kw['_type'] = _type
|
||||
kw['features'] = Utils.to_list(kw.get('features', [])) + Utils.to_list(sniff_features(**kw))
|
||||
|
||||
@conf
|
||||
def program(bld, *k, **kw):
|
||||
"""
|
||||
Alias for creating programs by looking at the file extensions::
|
||||
|
||||
def build(bld):
|
||||
bld.program(source='foo.c', target='app')
|
||||
# equivalent to:
|
||||
# bld(features='c cprogram', source='foo.c', target='app')
|
||||
|
||||
"""
|
||||
set_features(kw, 'program')
|
||||
return bld(*k, **kw)
|
||||
|
||||
@conf
|
||||
def shlib(bld, *k, **kw):
|
||||
"""
|
||||
Alias for creating shared libraries by looking at the file extensions::
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(source='foo.c', target='app')
|
||||
# equivalent to:
|
||||
# bld(features='c cshlib', source='foo.c', target='app')
|
||||
|
||||
"""
|
||||
set_features(kw, 'shlib')
|
||||
return bld(*k, **kw)
|
||||
|
||||
@conf
|
||||
def stlib(bld, *k, **kw):
|
||||
"""
|
||||
Alias for creating static libraries by looking at the file extensions::
|
||||
|
||||
def build(bld):
|
||||
bld.stlib(source='foo.cpp', target='app')
|
||||
# equivalent to:
|
||||
# bld(features='cxx cxxstlib', source='foo.cpp', target='app')
|
||||
|
||||
"""
|
||||
set_features(kw, 'stlib')
|
||||
return bld(*k, **kw)
|
||||
|
||||
@conf
|
||||
def objects(bld, *k, **kw):
|
||||
"""
|
||||
Alias for creating object files by looking at the file extensions::
|
||||
|
||||
def build(bld):
|
||||
bld.objects(source='foo.c', target='app')
|
||||
# equivalent to:
|
||||
# bld(features='c', source='foo.c', target='app')
|
||||
|
||||
"""
|
||||
set_features(kw, 'objects')
|
||||
return bld(*k, **kw)
|
||||
|
||||
+1233
File diff suppressed because it is too large
Load Diff
+188
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy 2008-2010
|
||||
|
||||
"""
|
||||
MacOSX related tools
|
||||
"""
|
||||
|
||||
import os, shutil, sys, platform
|
||||
from waflib import TaskGen, Task, Build, Options, Utils, Errors
|
||||
from waflib.TaskGen import taskgen_method, feature, after_method, before_method
|
||||
|
||||
app_info = '''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
|
||||
<plist version="0.9">
|
||||
<dict>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Created by Waf</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>NOTE</key>
|
||||
<string>THIS IS A GENERATED FILE, DO NOT MODIFY</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>%s</string>
|
||||
</dict>
|
||||
</plist>
|
||||
'''
|
||||
"""
|
||||
plist template
|
||||
"""
|
||||
|
||||
@feature('c', 'cxx')
|
||||
def set_macosx_deployment_target(self):
|
||||
"""
|
||||
see WAF issue 285 and also and also http://trac.macports.org/ticket/17059
|
||||
"""
|
||||
if self.env['MACOSX_DEPLOYMENT_TARGET']:
|
||||
os.environ['MACOSX_DEPLOYMENT_TARGET'] = self.env['MACOSX_DEPLOYMENT_TARGET']
|
||||
elif 'MACOSX_DEPLOYMENT_TARGET' not in os.environ:
|
||||
if Utils.unversioned_sys_platform() == 'darwin':
|
||||
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '.'.join(platform.mac_ver()[0].split('.')[:2])
|
||||
|
||||
@taskgen_method
|
||||
def create_bundle_dirs(self, name, out):
|
||||
"""
|
||||
Create bundle folders, used by :py:func:`create_task_macplist` and :py:func:`create_task_macapp`
|
||||
"""
|
||||
bld = self.bld
|
||||
dir = out.parent.find_or_declare(name)
|
||||
dir.mkdir()
|
||||
macos = dir.find_or_declare(['Contents', 'MacOS'])
|
||||
macos.mkdir()
|
||||
return dir
|
||||
|
||||
def bundle_name_for_output(out):
|
||||
name = out.name
|
||||
k = name.rfind('.')
|
||||
if k >= 0:
|
||||
name = name[:k] + '.app'
|
||||
else:
|
||||
name = name + '.app'
|
||||
return name
|
||||
|
||||
@feature('cprogram', 'cxxprogram')
|
||||
@after_method('apply_link')
|
||||
def create_task_macapp(self):
|
||||
"""
|
||||
To compile an executable into a Mac application (a .app), set its *mac_app* attribute::
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(source='a.c', target='foo', mac_app = True)
|
||||
|
||||
To force *all* executables to be transformed into Mac applications::
|
||||
|
||||
def build(bld):
|
||||
bld.env.MACAPP = True
|
||||
bld.shlib(source='a.c', target='foo')
|
||||
"""
|
||||
if self.env['MACAPP'] or getattr(self, 'mac_app', False):
|
||||
out = self.link_task.outputs[0]
|
||||
|
||||
name = bundle_name_for_output(out)
|
||||
dir = self.create_bundle_dirs(name, out)
|
||||
|
||||
n1 = dir.find_or_declare(['Contents', 'MacOS', out.name])
|
||||
|
||||
self.apptask = self.create_task('macapp', self.link_task.outputs, n1)
|
||||
inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/MacOS/' % name
|
||||
self.bld.install_files(inst_to, n1, chmod=Utils.O755)
|
||||
|
||||
if getattr(self, 'mac_resources', None):
|
||||
res_dir = n1.parent.parent.make_node('Resources')
|
||||
inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Resources' % name
|
||||
for x in self.to_list(self.mac_resources):
|
||||
node = self.path.find_node(x)
|
||||
if not node:
|
||||
raise Errors.WafError('Missing mac_resource %r in %r' % (x, self))
|
||||
|
||||
parent = node.parent
|
||||
if os.path.isdir(node.abspath()):
|
||||
nodes = node.ant_glob('**')
|
||||
else:
|
||||
nodes = [node]
|
||||
for node in nodes:
|
||||
rel = node.path_from(parent)
|
||||
tsk = self.create_task('macapp', node, res_dir.make_node(rel))
|
||||
self.bld.install_as(inst_to + '/%s' % rel, node)
|
||||
|
||||
if getattr(self.bld, 'is_install', None):
|
||||
# disable the normal binary installation
|
||||
self.install_task.hasrun = Task.SKIP_ME
|
||||
|
||||
@feature('cprogram', 'cxxprogram')
|
||||
@after_method('apply_link')
|
||||
def create_task_macplist(self):
|
||||
"""
|
||||
Create a :py:class:`waflib.Tools.c_osx.macplist` instance.
|
||||
"""
|
||||
if self.env['MACAPP'] or getattr(self, 'mac_app', False):
|
||||
out = self.link_task.outputs[0]
|
||||
|
||||
name = bundle_name_for_output(out)
|
||||
|
||||
dir = self.create_bundle_dirs(name, out)
|
||||
n1 = dir.find_or_declare(['Contents', 'Info.plist'])
|
||||
self.plisttask = plisttask = self.create_task('macplist', [], n1)
|
||||
|
||||
if getattr(self, 'mac_plist', False):
|
||||
node = self.path.find_resource(self.mac_plist)
|
||||
if node:
|
||||
plisttask.inputs.append(node)
|
||||
else:
|
||||
plisttask.code = self.mac_plist
|
||||
else:
|
||||
plisttask.code = app_info % self.link_task.outputs[0].name
|
||||
|
||||
inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/' % name
|
||||
self.bld.install_files(inst_to, n1)
|
||||
|
||||
@feature('cshlib', 'cxxshlib')
|
||||
@before_method('apply_link', 'propagate_uselib_vars')
|
||||
def apply_bundle(self):
|
||||
"""
|
||||
To make a bundled shared library (a ``.bundle``), set the *mac_bundle* attribute::
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(source='a.c', target='foo', mac_bundle = True)
|
||||
|
||||
To force *all* executables to be transformed into bundles::
|
||||
|
||||
def build(bld):
|
||||
bld.env.MACBUNDLE = True
|
||||
bld.shlib(source='a.c', target='foo')
|
||||
"""
|
||||
if self.env['MACBUNDLE'] or getattr(self, 'mac_bundle', False):
|
||||
self.env['LINKFLAGS_cshlib'] = self.env['LINKFLAGS_cxxshlib'] = [] # disable the '-dynamiclib' flag
|
||||
self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['macbundle_PATTERN']
|
||||
use = self.use = self.to_list(getattr(self, 'use', []))
|
||||
if not 'MACBUNDLE' in use:
|
||||
use.append('MACBUNDLE')
|
||||
|
||||
app_dirs = ['Contents', 'Contents/MacOS', 'Contents/Resources']
|
||||
|
||||
class macapp(Task.Task):
|
||||
"""
|
||||
Create mac applications
|
||||
"""
|
||||
color = 'PINK'
|
||||
def run(self):
|
||||
self.outputs[0].parent.mkdir()
|
||||
shutil.copy2(self.inputs[0].srcpath(), self.outputs[0].abspath())
|
||||
|
||||
class macplist(Task.Task):
|
||||
"""
|
||||
Create plist files
|
||||
"""
|
||||
color = 'PINK'
|
||||
ext_in = ['.bin']
|
||||
def run(self):
|
||||
if getattr(self, 'code', None):
|
||||
txt = self.code
|
||||
else:
|
||||
txt = self.inputs[0].read()
|
||||
self.outputs[0].write(txt)
|
||||
|
||||
+1029
File diff suppressed because it is too large
Load Diff
+226
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
"""
|
||||
Various configuration tests.
|
||||
"""
|
||||
|
||||
from waflib import Task
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, before_method, after_method
|
||||
import sys
|
||||
|
||||
LIB_CODE = '''
|
||||
#ifdef _MSC_VER
|
||||
#define testEXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define testEXPORT
|
||||
#endif
|
||||
testEXPORT int lib_func(void) { return 9; }
|
||||
'''
|
||||
|
||||
MAIN_CODE = '''
|
||||
#ifdef _MSC_VER
|
||||
#define testEXPORT __declspec(dllimport)
|
||||
#else
|
||||
#define testEXPORT
|
||||
#endif
|
||||
testEXPORT int lib_func(void);
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
return !(lib_func() == 9);
|
||||
}
|
||||
'''
|
||||
|
||||
@feature('link_lib_test')
|
||||
@before_method('process_source')
|
||||
def link_lib_test_fun(self):
|
||||
"""
|
||||
The configuration test :py:func:`waflib.Tools.ccroot.run_c_code` declares a unique task generator,
|
||||
so we need to create other task generators from here to check if the linker is able to link libraries.
|
||||
"""
|
||||
def write_test_file(task):
|
||||
task.outputs[0].write(task.generator.code)
|
||||
|
||||
rpath = []
|
||||
if getattr(self, 'add_rpath', False):
|
||||
rpath = [self.bld.path.get_bld().abspath()]
|
||||
|
||||
mode = self.mode
|
||||
m = '%s %s' % (mode, mode)
|
||||
ex = self.test_exec and 'test_exec' or ''
|
||||
bld = self.bld
|
||||
bld(rule=write_test_file, target='test.' + mode, code=LIB_CODE)
|
||||
bld(rule=write_test_file, target='main.' + mode, code=MAIN_CODE)
|
||||
bld(features='%sshlib' % m, source='test.' + mode, target='test')
|
||||
bld(features='%sprogram %s' % (m, ex), source='main.' + mode, target='app', use='test', rpath=rpath)
|
||||
|
||||
@conf
|
||||
def check_library(self, mode=None, test_exec=True):
|
||||
"""
|
||||
Check if libraries can be linked with the current linker. Uses :py:func:`waflib.Tools.c_tests.link_lib_test_fun`.
|
||||
|
||||
:param mode: c or cxx or d
|
||||
:type mode: string
|
||||
"""
|
||||
if not mode:
|
||||
mode = 'c'
|
||||
if self.env.CXX:
|
||||
mode = 'cxx'
|
||||
self.check(
|
||||
compile_filename = [],
|
||||
features = 'link_lib_test',
|
||||
msg = 'Checking for libraries',
|
||||
mode = mode,
|
||||
test_exec = test_exec,
|
||||
)
|
||||
|
||||
########################################################################################
|
||||
|
||||
INLINE_CODE = '''
|
||||
typedef int foo_t;
|
||||
static %s foo_t static_foo () {return 0; }
|
||||
%s foo_t foo () {
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
INLINE_VALUES = ['inline', '__inline__', '__inline']
|
||||
|
||||
@conf
|
||||
def check_inline(self, **kw):
|
||||
"""
|
||||
Check for the right value for inline macro.
|
||||
Define INLINE_MACRO to 1 if the define is found.
|
||||
If the inline macro is not 'inline', add a define to the ``config.h`` (#define inline __inline__)
|
||||
|
||||
:param define_name: define INLINE_MACRO by default to 1 if the macro is defined
|
||||
:type define_name: string
|
||||
:param features: by default *c* or *cxx* depending on the compiler present
|
||||
:type features: list of string
|
||||
"""
|
||||
|
||||
self.start_msg('Checking for inline')
|
||||
|
||||
if not 'define_name' in kw:
|
||||
kw['define_name'] = 'INLINE_MACRO'
|
||||
if not 'features' in kw:
|
||||
if self.env.CXX:
|
||||
kw['features'] = ['cxx']
|
||||
else:
|
||||
kw['features'] = ['c']
|
||||
|
||||
for x in INLINE_VALUES:
|
||||
kw['fragment'] = INLINE_CODE % (x, x)
|
||||
|
||||
try:
|
||||
self.check(**kw)
|
||||
except self.errors.ConfigurationError:
|
||||
continue
|
||||
else:
|
||||
self.end_msg(x)
|
||||
if x != 'inline':
|
||||
self.define('inline', x, quote=False)
|
||||
return x
|
||||
self.fatal('could not use inline functions')
|
||||
|
||||
########################################################################################
|
||||
|
||||
LARGE_FRAGMENT = '''#include <unistd.h>
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
return !(sizeof(off_t) >= 8);
|
||||
}
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_large_file(self, **kw):
|
||||
"""
|
||||
Check for large file support and define the macro HAVE_LARGEFILE
|
||||
The test is skipped on win32 systems (DEST_BINFMT == pe).
|
||||
|
||||
:param define_name: define to set, by default *HAVE_LARGEFILE*
|
||||
:type define_name: string
|
||||
:param execute: execute the test (yes by default)
|
||||
:type execute: bool
|
||||
"""
|
||||
|
||||
if not 'define_name' in kw:
|
||||
kw['define_name'] = 'HAVE_LARGEFILE'
|
||||
if not 'execute' in kw:
|
||||
kw['execute'] = True
|
||||
|
||||
if not 'features' in kw:
|
||||
if self.env.CXX:
|
||||
kw['features'] = ['cxx', 'cxxprogram']
|
||||
else:
|
||||
kw['features'] = ['c', 'cprogram']
|
||||
|
||||
kw['fragment'] = LARGE_FRAGMENT
|
||||
|
||||
kw['msg'] = 'Checking for large file support'
|
||||
ret = True
|
||||
try:
|
||||
if self.env.DEST_BINFMT != 'pe':
|
||||
ret = self.check(**kw)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
if ret:
|
||||
return True
|
||||
|
||||
kw['msg'] = 'Checking for -D_FILE_OFFSET_BITS=64'
|
||||
kw['defines'] = ['_FILE_OFFSET_BITS=64']
|
||||
try:
|
||||
ret = self.check(**kw)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
self.define('_FILE_OFFSET_BITS', 64)
|
||||
return ret
|
||||
|
||||
self.fatal('There is no support for large files')
|
||||
|
||||
########################################################################################
|
||||
|
||||
ENDIAN_FRAGMENT = '''
|
||||
short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
|
||||
short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
|
||||
int use_ascii (int i) {
|
||||
return ascii_mm[i] + ascii_ii[i];
|
||||
}
|
||||
short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
|
||||
short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
|
||||
int use_ebcdic (int i) {
|
||||
return ebcdic_mm[i] + ebcdic_ii[i];
|
||||
}
|
||||
extern int foo;
|
||||
'''
|
||||
|
||||
class grep_for_endianness(Task.Task):
|
||||
color = 'PINK'
|
||||
def run(self):
|
||||
txt = self.inputs[0].read(flags='rb').decode('iso8859-1')
|
||||
if txt.find('LiTTleEnDian') > -1:
|
||||
self.generator.tmp.append('little')
|
||||
elif txt.find('BIGenDianSyS') > -1:
|
||||
self.generator.tmp.append('big')
|
||||
else:
|
||||
return -1
|
||||
|
||||
@feature('grep_for_endianness')
|
||||
@after_method('process_source')
|
||||
def grep_for_endianness_fun(self):
|
||||
self.create_task('grep_for_endianness', self.compiled_tasks[0].outputs[0])
|
||||
|
||||
@conf
|
||||
def check_endianness(self):
|
||||
"""
|
||||
Execute a configuration test to determine the endianness
|
||||
"""
|
||||
tmp = []
|
||||
def check_msg(self):
|
||||
return tmp[0]
|
||||
self.check(fragment=ENDIAN_FRAGMENT, features='c grep_for_endianness', msg="Checking for endianness", define='ENDIANNESS', tmp=tmp, okmsg=check_msg)
|
||||
return tmp[0]
|
||||
|
||||
+653
@@ -0,0 +1,653 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
Classes and methods shared by tools providing support for C-like language such
|
||||
as C/C++/D/Assembly/Go (this support module is almost never used alone).
|
||||
"""
|
||||
|
||||
import os, re
|
||||
from waflib import Task, Utils, Node, Errors
|
||||
from waflib.TaskGen import after_method, before_method, feature, taskgen_method, extension
|
||||
from waflib.Tools import c_aliases, c_preproc, c_config, c_osx, c_tests
|
||||
from waflib.Configure import conf
|
||||
|
||||
SYSTEM_LIB_PATHS = ['/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib']
|
||||
|
||||
USELIB_VARS = Utils.defaultdict(set)
|
||||
"""
|
||||
Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`.
|
||||
"""
|
||||
|
||||
USELIB_VARS['c'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH'])
|
||||
USELIB_VARS['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH'])
|
||||
USELIB_VARS['d'] = set(['INCLUDES', 'DFLAGS'])
|
||||
USELIB_VARS['includes'] = set(['INCLUDES', 'FRAMEWORKPATH', 'ARCH'])
|
||||
|
||||
USELIB_VARS['cprogram'] = USELIB_VARS['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])
|
||||
USELIB_VARS['cshlib'] = USELIB_VARS['cxxshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])
|
||||
USELIB_VARS['cstlib'] = USELIB_VARS['cxxstlib'] = set(['ARFLAGS', 'LINKDEPS'])
|
||||
|
||||
USELIB_VARS['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
|
||||
USELIB_VARS['dshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
|
||||
USELIB_VARS['dstlib'] = set(['ARFLAGS', 'LINKDEPS'])
|
||||
|
||||
USELIB_VARS['asm'] = set(['ASFLAGS'])
|
||||
|
||||
# =================================================================================================
|
||||
|
||||
@taskgen_method
|
||||
def create_compiled_task(self, name, node):
|
||||
"""
|
||||
Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension).
|
||||
The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link`
|
||||
|
||||
:param name: name of the task class
|
||||
:type name: string
|
||||
:param node: the file to compile
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
:return: The task created
|
||||
:rtype: :py:class:`waflib.Task.Task`
|
||||
"""
|
||||
out = '%s.%d.o' % (node.name, self.idx)
|
||||
task = self.create_task(name, node, node.parent.find_or_declare(out))
|
||||
try:
|
||||
self.compiled_tasks.append(task)
|
||||
except AttributeError:
|
||||
self.compiled_tasks = [task]
|
||||
return task
|
||||
|
||||
@taskgen_method
|
||||
def to_incnodes(self, inlst):
|
||||
"""
|
||||
Task generator method provided to convert a list of string/nodes into a list of includes folders.
|
||||
|
||||
The paths are assumed to be relative to the task generator path, except if they begin by **#**
|
||||
in which case they are searched from the top-level directory (``bld.srcnode``).
|
||||
The folders are simply assumed to be existing.
|
||||
|
||||
The node objects in the list are returned in the output list. The strings are converted
|
||||
into node objects if possible. The node is searched from the source directory, and if a match is found,
|
||||
the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored.
|
||||
|
||||
:param inlst: list of folders
|
||||
:type inlst: space-delimited string or a list of string/nodes
|
||||
:rtype: list of :py:class:`waflib.Node.Node`
|
||||
:return: list of include folders as nodes
|
||||
"""
|
||||
lst = []
|
||||
seen = set([])
|
||||
for x in self.to_list(inlst):
|
||||
if x in seen or not x:
|
||||
continue
|
||||
seen.add(x)
|
||||
|
||||
if isinstance(x, Node.Node):
|
||||
lst.append(x)
|
||||
else:
|
||||
if os.path.isabs(x):
|
||||
lst.append(self.bld.root.make_node(x) or x)
|
||||
else:
|
||||
if x[0] == '#':
|
||||
p = self.bld.bldnode.make_node(x[1:])
|
||||
v = self.bld.srcnode.make_node(x[1:])
|
||||
else:
|
||||
p = self.path.get_bld().make_node(x)
|
||||
v = self.path.make_node(x)
|
||||
if p.is_child_of(self.bld.bldnode):
|
||||
p.mkdir()
|
||||
lst.append(p)
|
||||
lst.append(v)
|
||||
return lst
|
||||
|
||||
@feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')
|
||||
@after_method('propagate_uselib_vars', 'process_source')
|
||||
def apply_incpaths(self):
|
||||
"""
|
||||
Task generator method that processes the attribute *includes*::
|
||||
|
||||
tg = bld(features='includes', includes='.')
|
||||
|
||||
The folders only need to be relative to the current directory, the equivalent build directory is
|
||||
added automatically (for headers created in the build directory). This enable using a build directory
|
||||
or not (``top == out``).
|
||||
|
||||
This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``,
|
||||
and the list of include paths in ``tg.env.INCLUDES``.
|
||||
"""
|
||||
|
||||
lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
|
||||
self.includes_nodes = lst
|
||||
self.env['INCPATHS'] = [x.abspath() for x in lst]
|
||||
|
||||
class link_task(Task.Task):
|
||||
"""
|
||||
Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`.
|
||||
|
||||
.. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib
|
||||
"""
|
||||
color = 'YELLOW'
|
||||
|
||||
inst_to = None
|
||||
"""Default installation path for the link task outputs, or None to disable"""
|
||||
|
||||
chmod = Utils.O755
|
||||
"""Default installation mode for the link task outputs"""
|
||||
|
||||
def add_target(self, target):
|
||||
"""
|
||||
Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.
|
||||
The settings are retrieved from ``env.clsname_PATTERN``
|
||||
"""
|
||||
if isinstance(target, str):
|
||||
pattern = self.env[self.__class__.__name__ + '_PATTERN']
|
||||
if not pattern:
|
||||
pattern = '%s'
|
||||
folder, name = os.path.split(target)
|
||||
|
||||
if self.__class__.__name__.find('shlib') > 0:
|
||||
if self.env.DEST_BINFMT == 'pe' and getattr(self.generator, 'vnum', None):
|
||||
# include the version in the dll file name,
|
||||
# the import lib file name stays unversionned.
|
||||
name = name + '-' + self.generator.vnum.split('.')[0]
|
||||
|
||||
tmp = folder + os.sep + pattern % name
|
||||
target = self.generator.path.find_or_declare(tmp)
|
||||
self.set_outputs(target)
|
||||
|
||||
class stlink_task(link_task):
|
||||
"""
|
||||
Base for static link tasks, which use *ar* most of the time.
|
||||
The target is always removed before being written.
|
||||
"""
|
||||
run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
|
||||
|
||||
def rm_tgt(cls):
|
||||
old = cls.run
|
||||
def wrap(self):
|
||||
try: os.remove(self.outputs[0].abspath())
|
||||
except OSError: pass
|
||||
return old(self)
|
||||
setattr(cls, 'run', wrap)
|
||||
rm_tgt(stlink_task)
|
||||
|
||||
@feature('c', 'cxx', 'd', 'fc', 'asm')
|
||||
@after_method('process_source')
|
||||
def apply_link(self):
|
||||
"""
|
||||
Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and
|
||||
use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task
|
||||
matching a name from the attribute *features*, for example::
|
||||
|
||||
def build(bld):
|
||||
tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')
|
||||
|
||||
will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`
|
||||
"""
|
||||
|
||||
for x in self.features:
|
||||
if x == 'cprogram' and 'cxx' in self.features: # limited compat
|
||||
x = 'cxxprogram'
|
||||
elif x == 'cshlib' and 'cxx' in self.features:
|
||||
x = 'cxxshlib'
|
||||
|
||||
if x in Task.classes:
|
||||
if issubclass(Task.classes[x], link_task):
|
||||
link = x
|
||||
break
|
||||
else:
|
||||
return
|
||||
|
||||
objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])]
|
||||
self.link_task = self.create_task(link, objs)
|
||||
self.link_task.add_target(self.target)
|
||||
|
||||
# remember that the install paths are given by the task generators
|
||||
try:
|
||||
inst_to = self.install_path
|
||||
except AttributeError:
|
||||
inst_to = self.link_task.__class__.inst_to
|
||||
if inst_to:
|
||||
# install a copy of the node list we have at this moment (implib not added)
|
||||
self.install_task = self.bld.install_files(inst_to, self.link_task.outputs[:], env=self.env, chmod=self.link_task.chmod)
|
||||
|
||||
@taskgen_method
|
||||
def use_rec(self, name, **kw):
|
||||
"""
|
||||
Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``
|
||||
"""
|
||||
|
||||
if name in self.tmp_use_not or name in self.tmp_use_seen:
|
||||
return
|
||||
|
||||
try:
|
||||
y = self.bld.get_tgen_by_name(name)
|
||||
except Errors.WafError:
|
||||
self.uselib.append(name)
|
||||
self.tmp_use_not.add(name)
|
||||
return
|
||||
|
||||
self.tmp_use_seen.append(name)
|
||||
y.post()
|
||||
|
||||
# bind temporary attributes on the task generator
|
||||
y.tmp_use_objects = objects = kw.get('objects', True)
|
||||
y.tmp_use_stlib = stlib = kw.get('stlib', True)
|
||||
try:
|
||||
link_task = y.link_task
|
||||
except AttributeError:
|
||||
y.tmp_use_var = ''
|
||||
else:
|
||||
objects = False
|
||||
if not isinstance(link_task, stlink_task):
|
||||
stlib = False
|
||||
y.tmp_use_var = 'LIB'
|
||||
else:
|
||||
y.tmp_use_var = 'STLIB'
|
||||
|
||||
p = self.tmp_use_prec
|
||||
for x in self.to_list(getattr(y, 'use', [])):
|
||||
try:
|
||||
p[x].append(name)
|
||||
except KeyError:
|
||||
p[x] = [name]
|
||||
self.use_rec(x, objects=objects, stlib=stlib)
|
||||
|
||||
@feature('c', 'cxx', 'd', 'use', 'fc')
|
||||
@before_method('apply_incpaths', 'propagate_uselib_vars')
|
||||
@after_method('apply_link', 'process_source')
|
||||
def process_use(self):
|
||||
"""
|
||||
Process the ``use`` attribute which contains a list of task generator names::
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(source='a.c', target='lib1')
|
||||
bld.program(source='main.c', target='app', use='lib1')
|
||||
|
||||
See :py:func:`waflib.Tools.ccroot.use_rec`.
|
||||
"""
|
||||
|
||||
use_not = self.tmp_use_not = set([])
|
||||
self.tmp_use_seen = [] # we would like an ordered set
|
||||
use_prec = self.tmp_use_prec = {}
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
self.includes = self.to_list(getattr(self, 'includes', []))
|
||||
names = self.to_list(getattr(self, 'use', []))
|
||||
|
||||
for x in names:
|
||||
self.use_rec(x)
|
||||
|
||||
for x in use_not:
|
||||
if x in use_prec:
|
||||
del use_prec[x]
|
||||
|
||||
# topological sort
|
||||
out = []
|
||||
tmp = []
|
||||
for x in self.tmp_use_seen:
|
||||
for k in use_prec.values():
|
||||
if x in k:
|
||||
break
|
||||
else:
|
||||
tmp.append(x)
|
||||
|
||||
while tmp:
|
||||
e = tmp.pop()
|
||||
out.append(e)
|
||||
try:
|
||||
nlst = use_prec[e]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
del use_prec[e]
|
||||
for x in nlst:
|
||||
for y in use_prec:
|
||||
if x in use_prec[y]:
|
||||
break
|
||||
else:
|
||||
tmp.append(x)
|
||||
if use_prec:
|
||||
raise Errors.WafError('Cycle detected in the use processing %r' % use_prec)
|
||||
out.reverse()
|
||||
|
||||
link_task = getattr(self, 'link_task', None)
|
||||
for x in out:
|
||||
y = self.bld.get_tgen_by_name(x)
|
||||
var = y.tmp_use_var
|
||||
if var and link_task:
|
||||
if var == 'LIB' or y.tmp_use_stlib:
|
||||
self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]])
|
||||
self.link_task.dep_nodes.extend(y.link_task.outputs)
|
||||
tmp_path = y.link_task.outputs[0].parent.path_from(self.bld.bldnode)
|
||||
self.env.append_value(var + 'PATH', [tmp_path])
|
||||
else:
|
||||
if y.tmp_use_objects:
|
||||
self.add_objects_from_tgen(y)
|
||||
|
||||
if getattr(y, 'export_includes', None):
|
||||
self.includes.extend(y.to_incnodes(y.export_includes))
|
||||
|
||||
if getattr(y, 'export_defines', None):
|
||||
self.env.append_value('DEFINES', self.to_list(y.export_defines))
|
||||
|
||||
|
||||
# and finally, add the uselib variables (no recursion needed)
|
||||
for x in names:
|
||||
try:
|
||||
y = self.bld.get_tgen_by_name(x)
|
||||
except Exception:
|
||||
if not self.env['STLIB_' + x] and not x in self.uselib:
|
||||
self.uselib.append(x)
|
||||
else:
|
||||
for k in self.to_list(getattr(y, 'uselib', [])):
|
||||
if not self.env['STLIB_' + k] and not k in self.uselib:
|
||||
self.uselib.append(k)
|
||||
|
||||
@taskgen_method
|
||||
def accept_node_to_link(self, node):
|
||||
"""
|
||||
PRIVATE INTERNAL USE ONLY
|
||||
"""
|
||||
return not node.name.endswith('.pdb')
|
||||
|
||||
@taskgen_method
|
||||
def add_objects_from_tgen(self, tg):
|
||||
"""
|
||||
Add the objects from the depending compiled tasks as link task inputs.
|
||||
|
||||
Some objects are filtered: for instance, .pdb files are added
|
||||
to the compiled tasks but not to the link tasks (to avoid errors)
|
||||
PRIVATE INTERNAL USE ONLY
|
||||
"""
|
||||
try:
|
||||
link_task = self.link_task
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
for tsk in getattr(tg, 'compiled_tasks', []):
|
||||
for x in tsk.outputs:
|
||||
if self.accept_node_to_link(x):
|
||||
link_task.inputs.append(x)
|
||||
|
||||
@taskgen_method
|
||||
def get_uselib_vars(self):
|
||||
"""
|
||||
:return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)
|
||||
:rtype: list of string
|
||||
"""
|
||||
_vars = set([])
|
||||
for x in self.features:
|
||||
if x in USELIB_VARS:
|
||||
_vars |= USELIB_VARS[x]
|
||||
return _vars
|
||||
|
||||
@feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib', 'asm')
|
||||
@after_method('process_use')
|
||||
def propagate_uselib_vars(self):
|
||||
"""
|
||||
Process uselib variables for adding flags. For example, the following target::
|
||||
|
||||
def build(bld):
|
||||
bld.env.AFLAGS_aaa = ['bar']
|
||||
from waflib.Tools.ccroot import USELIB_VARS
|
||||
USELIB_VARS['aaa'] = set('AFLAGS')
|
||||
|
||||
tg = bld(features='aaa', aflags='test')
|
||||
|
||||
The *aflags* attribute will be processed and this method will set::
|
||||
|
||||
tg.env.AFLAGS = ['bar', 'test']
|
||||
"""
|
||||
_vars = self.get_uselib_vars()
|
||||
env = self.env
|
||||
|
||||
for x in _vars:
|
||||
y = x.lower()
|
||||
env.append_unique(x, self.to_list(getattr(self, y, [])))
|
||||
|
||||
for x in self.features:
|
||||
for var in _vars:
|
||||
compvar = '%s_%s' % (var, x)
|
||||
env.append_value(var, env[compvar])
|
||||
|
||||
for x in self.to_list(getattr(self, 'uselib', [])):
|
||||
for v in _vars:
|
||||
env.append_value(v, env[v + '_' + x])
|
||||
|
||||
# ============ the code above must not know anything about import libs ==========
|
||||
|
||||
@feature('cshlib', 'cxxshlib', 'fcshlib')
|
||||
@after_method('apply_link')
|
||||
def apply_implib(self):
|
||||
"""
|
||||
Handle dlls and their import libs on Windows-like systems.
|
||||
|
||||
A ``.dll.a`` file called *import library* is generated.
|
||||
It must be installed as it is required for linking the library.
|
||||
"""
|
||||
if not self.env.DEST_BINFMT == 'pe':
|
||||
return
|
||||
|
||||
dll = self.link_task.outputs[0]
|
||||
if isinstance(self.target, Node.Node):
|
||||
name = self.target.name
|
||||
else:
|
||||
name = os.path.split(self.target)[1]
|
||||
implib = self.env['implib_PATTERN'] % name
|
||||
implib = dll.parent.find_or_declare(implib)
|
||||
self.env.append_value('LINKFLAGS', self.env['IMPLIB_ST'] % implib.bldpath())
|
||||
self.link_task.outputs.append(implib)
|
||||
|
||||
if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe':
|
||||
node = self.path.find_resource(self.defs)
|
||||
if not node:
|
||||
raise Errors.WafError('invalid def file %r' % self.defs)
|
||||
if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
|
||||
self.env.append_value('LINKFLAGS', '/def:%s' % node.path_from(self.bld.bldnode))
|
||||
self.link_task.dep_nodes.append(node)
|
||||
else:
|
||||
#gcc for windows takes *.def file a an input without any special flag
|
||||
self.link_task.inputs.append(node)
|
||||
|
||||
try:
|
||||
inst_to = self.install_path
|
||||
except AttributeError:
|
||||
inst_to = self.link_task.__class__.inst_to
|
||||
if not inst_to:
|
||||
return
|
||||
|
||||
self.implib_install_task = self.bld.install_as('${LIBDIR}/%s' % implib.name, implib, self.env)
|
||||
|
||||
# ============ the code above must not know anything about vnum processing on unix platforms =========
|
||||
|
||||
re_vnum = re.compile('^([1-9]\\d*|0)[.]([1-9]\\d*|0)[.]([1-9]\\d*|0)$')
|
||||
@feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
|
||||
@after_method('apply_link', 'propagate_uselib_vars')
|
||||
def apply_vnum(self):
|
||||
"""
|
||||
Enforce version numbering on shared libraries. The valid version numbers must have at most two dots::
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(source='a.c', target='foo', vnum='14.15.16')
|
||||
|
||||
In this example, ``libfoo.so`` is installed as ``libfoo.so.1.2.3``, and the following symbolic links are created:
|
||||
|
||||
* ``libfoo.so → libfoo.so.1.2.3``
|
||||
* ``libfoo.so.1 → libfoo.so.1.2.3``
|
||||
"""
|
||||
if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
|
||||
return
|
||||
|
||||
link = self.link_task
|
||||
if not re_vnum.match(self.vnum):
|
||||
raise Errors.WafError('Invalid version %r for %r' % (self.vnum, self))
|
||||
nums = self.vnum.split('.')
|
||||
node = link.outputs[0]
|
||||
|
||||
libname = node.name
|
||||
if libname.endswith('.dylib'):
|
||||
name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
|
||||
name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
|
||||
else:
|
||||
name3 = libname + '.' + self.vnum
|
||||
name2 = libname + '.' + nums[0]
|
||||
|
||||
# add the so name for the ld linker - to disable, just unset env.SONAME_ST
|
||||
if self.env.SONAME_ST:
|
||||
v = self.env.SONAME_ST % name2
|
||||
self.env.append_value('LINKFLAGS', v.split())
|
||||
|
||||
# the following task is just to enable execution from the build dir :-/
|
||||
self.create_task('vnum', node, [node.parent.find_or_declare(name2), node.parent.find_or_declare(name3)])
|
||||
|
||||
if getattr(self, 'install_task', None):
|
||||
self.install_task.hasrun = Task.SKIP_ME
|
||||
bld = self.bld
|
||||
path = self.install_task.dest
|
||||
t1 = bld.install_as(path + os.sep + name3, node, env=self.env, chmod=self.link_task.chmod)
|
||||
t2 = bld.symlink_as(path + os.sep + name2, name3)
|
||||
t3 = bld.symlink_as(path + os.sep + libname, name3)
|
||||
self.vnum_install_task = (t1, t2, t3)
|
||||
|
||||
if '-dynamiclib' in self.env['LINKFLAGS']:
|
||||
# this requires after(propagate_uselib_vars)
|
||||
try:
|
||||
inst_to = self.install_path
|
||||
except AttributeError:
|
||||
inst_to = self.link_task.__class__.inst_to
|
||||
if inst_to:
|
||||
p = Utils.subst_vars(inst_to, self.env)
|
||||
path = os.path.join(p, self.link_task.outputs[0].name)
|
||||
self.env.append_value('LINKFLAGS', ['-install_name', path])
|
||||
|
||||
class vnum(Task.Task):
|
||||
"""
|
||||
Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`
|
||||
"""
|
||||
color = 'CYAN'
|
||||
quient = True
|
||||
ext_in = ['.bin']
|
||||
def run(self):
|
||||
for x in self.outputs:
|
||||
path = x.abspath()
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.symlink(self.inputs[0].name, path)
|
||||
except OSError:
|
||||
return 1
|
||||
|
||||
class fake_shlib(link_task):
|
||||
"""
|
||||
Task used for reading a system library and adding the dependency on it
|
||||
"""
|
||||
def runnable_status(self):
|
||||
for t in self.run_after:
|
||||
if not t.hasrun:
|
||||
return Task.ASK_LATER
|
||||
|
||||
for x in self.outputs:
|
||||
x.sig = Utils.h_file(x.abspath())
|
||||
return Task.SKIP_ME
|
||||
|
||||
class fake_stlib(stlink_task):
|
||||
"""
|
||||
Task used for reading a system library and adding the dependency on it
|
||||
"""
|
||||
def runnable_status(self):
|
||||
for t in self.run_after:
|
||||
if not t.hasrun:
|
||||
return Task.ASK_LATER
|
||||
|
||||
for x in self.outputs:
|
||||
x.sig = Utils.h_file(x.abspath())
|
||||
return Task.SKIP_ME
|
||||
|
||||
@conf
|
||||
def read_shlib(self, name, paths=[], export_includes=[], export_defines=[]):
|
||||
"""
|
||||
Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::
|
||||
|
||||
def build(bld):
|
||||
bld.read_shlib('m')
|
||||
bld.program(source='main.c', use='m')
|
||||
"""
|
||||
return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib', export_includes=export_includes, export_defines=export_defines)
|
||||
|
||||
@conf
|
||||
def read_stlib(self, name, paths=[], export_includes=[], export_defines=[]):
|
||||
"""
|
||||
Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.
|
||||
"""
|
||||
return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib', export_includes=export_includes, export_defines=export_defines)
|
||||
|
||||
lib_patterns = {
|
||||
'shlib' : ['lib%s.so', '%s.so', 'lib%s.dylib', 'lib%s.dll', '%s.dll'],
|
||||
'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],
|
||||
}
|
||||
|
||||
@feature('fake_lib')
|
||||
def process_lib(self):
|
||||
"""
|
||||
Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.
|
||||
"""
|
||||
node = None
|
||||
|
||||
names = [x % self.name for x in lib_patterns[self.lib_type]]
|
||||
for x in self.lib_paths + [self.path] + SYSTEM_LIB_PATHS:
|
||||
if not isinstance(x, Node.Node):
|
||||
x = self.bld.root.find_node(x) or self.path.find_node(x)
|
||||
if not x:
|
||||
continue
|
||||
|
||||
for y in names:
|
||||
node = x.find_node(y)
|
||||
if node:
|
||||
node.sig = Utils.h_file(node.abspath())
|
||||
break
|
||||
else:
|
||||
continue
|
||||
break
|
||||
else:
|
||||
raise Errors.WafError('could not find library %r' % self.name)
|
||||
self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node])
|
||||
self.target = self.name
|
||||
|
||||
|
||||
class fake_o(Task.Task):
|
||||
def runnable_status(self):
|
||||
return Task.SKIP_ME
|
||||
|
||||
@extension('.o', '.obj')
|
||||
def add_those_o_files(self, node):
|
||||
tsk = self.create_task('fake_o', [], node)
|
||||
try:
|
||||
self.compiled_tasks.append(tsk)
|
||||
except AttributeError:
|
||||
self.compiled_tasks = [tsk]
|
||||
|
||||
@feature('fake_obj')
|
||||
@before_method('process_source')
|
||||
def process_objs(self):
|
||||
"""
|
||||
Puts object files in the task generator outputs
|
||||
"""
|
||||
for node in self.to_nodes(self.source):
|
||||
self.add_those_o_files(node)
|
||||
self.source = []
|
||||
|
||||
@conf
|
||||
def read_object(self, obj):
|
||||
"""
|
||||
Read an object file, enabling injection in libs/programs. Will trigger a rebuild if the file changes.
|
||||
|
||||
:param obj: object file path, as string or Node
|
||||
"""
|
||||
if not isinstance(obj, self.path.__class__):
|
||||
obj = self.path.find_resource(obj)
|
||||
return self(features='fake_obj', source=obj, name=obj.name)
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Matthias Jahn jahn dôt matthias ât freenet dôt de, 2007 (pmarat)
|
||||
|
||||
"""
|
||||
Try to detect a C compiler from the list of supported compilers (gcc, msvc, etc)::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c')
|
||||
def configure(cnf):
|
||||
cnf.load('compiler_c')
|
||||
def build(bld):
|
||||
bld.program(source='main.c', target='app')
|
||||
|
||||
The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_c.c_compiler`. To register
|
||||
a new C compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c')
|
||||
def configure(cnf):
|
||||
from waflib.Tools.compiler_c import c_compiler
|
||||
c_compiler['win32'] = ['cfoo', 'msvc', 'gcc']
|
||||
cnf.load('compiler_c')
|
||||
def build(bld):
|
||||
bld.program(source='main.c', target='app')
|
||||
|
||||
Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using::
|
||||
|
||||
$ CC=clang waf configure
|
||||
"""
|
||||
|
||||
import os, sys, imp, types
|
||||
from waflib.Tools import ccroot
|
||||
from waflib import Utils, Configure
|
||||
from waflib.Logs import debug
|
||||
|
||||
c_compiler = {
|
||||
'win32': ['msvc', 'gcc'],
|
||||
'cygwin': ['gcc'],
|
||||
'darwin': ['gcc'],
|
||||
'aix': ['xlc', 'gcc'],
|
||||
'linux': ['gcc', 'icc'],
|
||||
'sunos': ['suncc', 'gcc'],
|
||||
'irix': ['gcc', 'irixcc'],
|
||||
'hpux': ['gcc'],
|
||||
'gnu': ['gcc'],
|
||||
'java': ['gcc', 'msvc', 'icc'],
|
||||
'default':['gcc'],
|
||||
}
|
||||
"""
|
||||
Dict mapping the platform names to waf tools finding specific compilers::
|
||||
|
||||
from waflib.Tools.compiler_c import c_compiler
|
||||
c_compiler['linux'] = ['gcc', 'icc', 'suncc']
|
||||
"""
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Try to find a suitable C compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
|
||||
"""
|
||||
try: test_for_compiler = conf.options.check_c_compiler
|
||||
except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_c')")
|
||||
for compiler in test_for_compiler.split():
|
||||
conf.env.stash()
|
||||
conf.start_msg('Checking for %r (c compiler)' % compiler)
|
||||
try:
|
||||
conf.load(compiler)
|
||||
except conf.errors.ConfigurationError as e:
|
||||
conf.env.revert()
|
||||
conf.end_msg(False)
|
||||
debug('compiler_c: %r' % e)
|
||||
else:
|
||||
if conf.env['CC']:
|
||||
conf.end_msg(conf.env.get_flat('CC'))
|
||||
conf.env['COMPILER_CC'] = compiler
|
||||
break
|
||||
conf.end_msg(False)
|
||||
else:
|
||||
conf.fatal('could not configure a c compiler!')
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Restrict the compiler detection from the command-line::
|
||||
|
||||
$ waf configure --check-c-compiler=gcc
|
||||
"""
|
||||
opt.load_special_tools('c_*.py', ban=['c_dumbpreproc.py'])
|
||||
global c_compiler
|
||||
build_platform = Utils.unversioned_sys_platform()
|
||||
possible_compiler_list = c_compiler[build_platform in c_compiler and build_platform or 'default']
|
||||
test_for_compiler = ' '.join(possible_compiler_list)
|
||||
cc_compiler_opts = opt.add_option_group("C Compiler Options")
|
||||
cc_compiler_opts.add_option('--check-c-compiler', default="%s" % test_for_compiler,
|
||||
help='On this platform (%s) the following C-Compiler will be checked by default: "%s"' % (build_platform, test_for_compiler),
|
||||
dest="check_c_compiler")
|
||||
for x in test_for_compiler.split():
|
||||
opt.load('%s' % x)
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Matthias Jahn jahn dôt matthias ât freenet dôt de 2007 (pmarat)
|
||||
|
||||
"""
|
||||
Try to detect a C++ compiler from the list of supported compilers (g++, msvc, etc)::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx')
|
||||
def configure(cnf):
|
||||
cnf.load('compiler_cxx')
|
||||
def build(bld):
|
||||
bld.program(source='main.cpp', target='app')
|
||||
|
||||
The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_cxx.cxx_compiler`. To register
|
||||
a new C++ compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx')
|
||||
def configure(cnf):
|
||||
from waflib.Tools.compiler_cxx import cxx_compiler
|
||||
cxx_compiler['win32'] = ['cfoo', 'msvc', 'gcc']
|
||||
cnf.load('compiler_cxx')
|
||||
def build(bld):
|
||||
bld.program(source='main.c', target='app')
|
||||
|
||||
Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using::
|
||||
|
||||
$ CXX=clang waf configure
|
||||
"""
|
||||
|
||||
|
||||
import os, sys, imp, types
|
||||
from waflib.Tools import ccroot
|
||||
from waflib import Utils, Configure
|
||||
from waflib.Logs import debug
|
||||
|
||||
cxx_compiler = {
|
||||
'win32': ['msvc', 'g++'],
|
||||
'cygwin': ['g++'],
|
||||
'darwin': ['g++'],
|
||||
'aix': ['xlc++', 'g++'],
|
||||
'linux': ['g++', 'icpc'],
|
||||
'sunos': ['sunc++', 'g++'],
|
||||
'irix': ['g++'],
|
||||
'hpux': ['g++'],
|
||||
'gnu': ['g++'],
|
||||
'java': ['g++', 'msvc', 'icpc'],
|
||||
'default': ['g++']
|
||||
}
|
||||
"""
|
||||
Dict mapping the platform names to waf tools finding specific compilers::
|
||||
|
||||
from waflib.Tools.compiler_cxx import cxx_compiler
|
||||
cxx_compiler['linux'] = ['gxx', 'icpc', 'suncxx']
|
||||
"""
|
||||
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Try to find a suitable C++ compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
|
||||
"""
|
||||
try: test_for_compiler = conf.options.check_cxx_compiler
|
||||
except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_cxx')")
|
||||
|
||||
for compiler in test_for_compiler.split():
|
||||
conf.env.stash()
|
||||
conf.start_msg('Checking for %r (c++ compiler)' % compiler)
|
||||
try:
|
||||
conf.load(compiler)
|
||||
except conf.errors.ConfigurationError as e:
|
||||
conf.env.revert()
|
||||
conf.end_msg(False)
|
||||
debug('compiler_cxx: %r' % e)
|
||||
else:
|
||||
if conf.env['CXX']:
|
||||
conf.end_msg(conf.env.get_flat('CXX'))
|
||||
conf.env['COMPILER_CXX'] = compiler
|
||||
break
|
||||
conf.end_msg(False)
|
||||
else:
|
||||
conf.fatal('could not configure a c++ compiler!')
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Restrict the compiler detection from the command-line::
|
||||
|
||||
$ waf configure --check-cxx-compiler=gxx
|
||||
"""
|
||||
opt.load_special_tools('cxx_*.py')
|
||||
global cxx_compiler
|
||||
build_platform = Utils.unversioned_sys_platform()
|
||||
possible_compiler_list = cxx_compiler[build_platform in cxx_compiler and build_platform or 'default']
|
||||
test_for_compiler = ' '.join(possible_compiler_list)
|
||||
cxx_compiler_opts = opt.add_option_group('C++ Compiler Options')
|
||||
cxx_compiler_opts.add_option('--check-cxx-compiler', default="%s" % test_for_compiler,
|
||||
help='On this platform (%s) the following C++ Compiler will be checked by default: "%s"' % (build_platform, test_for_compiler),
|
||||
dest="check_cxx_compiler")
|
||||
|
||||
for x in test_for_compiler.split():
|
||||
opt.load('%s' % x)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Carlos Rafael Giani, 2007 (dv)
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
"""
|
||||
Try to detect a D compiler from the list of supported compilers::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_d')
|
||||
def configure(cnf):
|
||||
cnf.load('compiler_d')
|
||||
def build(bld):
|
||||
bld.program(source='main.d', target='app')
|
||||
|
||||
Only three D compilers are really present at the moment:
|
||||
|
||||
* gdc
|
||||
* dmd, the ldc compiler having a very similar command-line interface
|
||||
* ldc2
|
||||
"""
|
||||
|
||||
import os, sys, imp, types
|
||||
from waflib import Utils, Configure, Options, Logs
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Try to find a suitable D compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
|
||||
"""
|
||||
for compiler in conf.options.dcheck.split(','):
|
||||
conf.env.stash()
|
||||
conf.start_msg('Checking for %r (d compiler)' % compiler)
|
||||
try:
|
||||
conf.load(compiler)
|
||||
except conf.errors.ConfigurationError as e:
|
||||
conf.env.revert()
|
||||
conf.end_msg(False)
|
||||
Logs.debug('compiler_d: %r' % e)
|
||||
else:
|
||||
if conf.env.D:
|
||||
conf.end_msg(conf.env.get_flat('D'))
|
||||
conf.env['COMPILER_D'] = compiler
|
||||
break
|
||||
conf.end_msg(False)
|
||||
else:
|
||||
conf.fatal('no suitable d compiler was found')
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Restrict the compiler detection from the command-line::
|
||||
|
||||
$ waf configure --check-d-compiler=dmd
|
||||
"""
|
||||
d_compiler_opts = opt.add_option_group('D Compiler Options')
|
||||
d_compiler_opts.add_option('--check-d-compiler', default='gdc,dmd,ldc2', action='store',
|
||||
help='check for the compiler [Default:gdc,dmd,ldc2]', dest='dcheck')
|
||||
for d_compiler in ['gdc', 'dmd', 'ldc2']:
|
||||
opt.load('%s' % d_compiler)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import os, sys, imp, types
|
||||
from waflib import Utils, Configure, Options, Logs, Errors
|
||||
from waflib.Tools import fc
|
||||
|
||||
fc_compiler = {
|
||||
'win32' : ['gfortran','ifort'],
|
||||
'darwin' : ['gfortran', 'g95', 'ifort'],
|
||||
'linux' : ['gfortran', 'g95', 'ifort'],
|
||||
'java' : ['gfortran', 'g95', 'ifort'],
|
||||
'default': ['gfortran'],
|
||||
'aix' : ['gfortran']
|
||||
}
|
||||
|
||||
def __list_possible_compiler(platform):
|
||||
try:
|
||||
return fc_compiler[platform]
|
||||
except KeyError:
|
||||
return fc_compiler["default"]
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Try to find a suitable Fortran compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
|
||||
"""
|
||||
try: test_for_compiler = conf.options.check_fc
|
||||
except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_fc')")
|
||||
for compiler in test_for_compiler.split():
|
||||
conf.env.stash()
|
||||
conf.start_msg('Checking for %r (fortran compiler)' % compiler)
|
||||
try:
|
||||
conf.load(compiler)
|
||||
except conf.errors.ConfigurationError as e:
|
||||
conf.env.revert()
|
||||
conf.end_msg(False)
|
||||
Logs.debug('compiler_fortran: %r' % e)
|
||||
else:
|
||||
if conf.env['FC']:
|
||||
conf.end_msg(conf.env.get_flat('FC'))
|
||||
conf.env.COMPILER_FORTRAN = compiler
|
||||
break
|
||||
conf.end_msg(False)
|
||||
else:
|
||||
conf.fatal('could not configure a fortran compiler!')
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Restrict the compiler detection from the command-line::
|
||||
|
||||
$ waf configure --check-fortran-compiler=ifort
|
||||
"""
|
||||
opt.load_special_tools('fc_*.py')
|
||||
build_platform = Utils.unversioned_sys_platform()
|
||||
detected_platform = Options.platform
|
||||
possible_compiler_list = __list_possible_compiler(detected_platform)
|
||||
test_for_compiler = ' '.join(possible_compiler_list)
|
||||
fortran_compiler_opts = opt.add_option_group("Fortran Compiler Options")
|
||||
fortran_compiler_opts.add_option('--check-fortran-compiler',
|
||||
default="%s" % test_for_compiler,
|
||||
help='On this platform (%s) the following Fortran Compiler will be checked by default: "%s"' % (detected_platform, test_for_compiler),
|
||||
dest="check_fc")
|
||||
|
||||
for compiler in test_for_compiler.split():
|
||||
opt.load('%s' % compiler)
|
||||
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
C# support. A simple example::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('cs')
|
||||
def build(bld):
|
||||
bld(features='cs', source='main.cs', gen='foo')
|
||||
|
||||
Note that the configuration may compile C# snippets::
|
||||
|
||||
FRAG = '''
|
||||
namespace Moo {
|
||||
public class Test { public static int Main(string[] args) { return 0; } }
|
||||
}'''
|
||||
def configure(conf):
|
||||
conf.check(features='cs', fragment=FRAG, compile_filename='test.cs', gen='test.exe',
|
||||
bintype='exe', csflags=['-pkg:gtk-sharp-2.0'], msg='Checking for Gtksharp support')
|
||||
"""
|
||||
|
||||
from waflib import Utils, Task, Options, Logs, Errors
|
||||
from waflib.TaskGen import before_method, after_method, feature
|
||||
from waflib.Tools import ccroot
|
||||
from waflib.Configure import conf
|
||||
import os, tempfile
|
||||
|
||||
ccroot.USELIB_VARS['cs'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES'])
|
||||
ccroot.lib_patterns['csshlib'] = ['%s']
|
||||
|
||||
@feature('cs')
|
||||
@before_method('process_source')
|
||||
def apply_cs(self):
|
||||
"""
|
||||
Create a C# task bound to the attribute *cs_task*. There can be only one C# task by task generator.
|
||||
"""
|
||||
cs_nodes = []
|
||||
no_nodes = []
|
||||
for x in self.to_nodes(self.source):
|
||||
if x.name.endswith('.cs'):
|
||||
cs_nodes.append(x)
|
||||
else:
|
||||
no_nodes.append(x)
|
||||
self.source = no_nodes
|
||||
|
||||
bintype = getattr(self, 'bintype', self.gen.endswith('.dll') and 'library' or 'exe')
|
||||
self.cs_task = tsk = self.create_task('mcs', cs_nodes, self.path.find_or_declare(self.gen))
|
||||
tsk.env.CSTYPE = '/target:%s' % bintype
|
||||
tsk.env.OUT = '/out:%s' % tsk.outputs[0].abspath()
|
||||
self.env.append_value('CSFLAGS', '/platform:%s' % getattr(self, 'platform', 'anycpu'))
|
||||
|
||||
inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}')
|
||||
if inst_to:
|
||||
# note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically
|
||||
mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644)
|
||||
self.install_task = self.bld.install_files(inst_to, self.cs_task.outputs[:], env=self.env, chmod=mod)
|
||||
|
||||
@feature('cs')
|
||||
@after_method('apply_cs')
|
||||
def use_cs(self):
|
||||
"""
|
||||
C# applications honor the **use** keyword::
|
||||
|
||||
def build(bld):
|
||||
bld(features='cs', source='My.cs', bintype='library', gen='my.dll', name='mylib')
|
||||
bld(features='cs', source='Hi.cs', includes='.', bintype='exe', gen='hi.exe', use='mylib', name='hi')
|
||||
"""
|
||||
names = self.to_list(getattr(self, 'use', []))
|
||||
get = self.bld.get_tgen_by_name
|
||||
for x in names:
|
||||
try:
|
||||
y = get(x)
|
||||
except Errors.WafError:
|
||||
self.env.append_value('CSFLAGS', '/reference:%s' % x)
|
||||
continue
|
||||
y.post()
|
||||
|
||||
tsk = getattr(y, 'cs_task', None) or getattr(y, 'link_task', None)
|
||||
if not tsk:
|
||||
self.bld.fatal('cs task has no link task for use %r' % self)
|
||||
self.cs_task.dep_nodes.extend(tsk.outputs) # dependency
|
||||
self.cs_task.set_run_after(tsk) # order (redundant, the order is infered from the nodes inputs/outputs)
|
||||
self.env.append_value('CSFLAGS', '/reference:%s' % tsk.outputs[0].abspath())
|
||||
|
||||
@feature('cs')
|
||||
@after_method('apply_cs', 'use_cs')
|
||||
def debug_cs(self):
|
||||
"""
|
||||
The C# targets may create .mdb or .pdb files::
|
||||
|
||||
def build(bld):
|
||||
bld(features='cs', source='My.cs', bintype='library', gen='my.dll', csdebug='full')
|
||||
# csdebug is a value in [True, 'full', 'pdbonly']
|
||||
"""
|
||||
csdebug = getattr(self, 'csdebug', self.env.CSDEBUG)
|
||||
if not csdebug:
|
||||
return
|
||||
|
||||
node = self.cs_task.outputs[0]
|
||||
if self.env.CS_NAME == 'mono':
|
||||
out = node.parent.find_or_declare(node.name + '.mdb')
|
||||
else:
|
||||
out = node.change_ext('.pdb')
|
||||
self.cs_task.outputs.append(out)
|
||||
try:
|
||||
self.install_task.source.append(out)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if csdebug == 'pdbonly':
|
||||
val = ['/debug+', '/debug:pdbonly']
|
||||
elif csdebug == 'full':
|
||||
val = ['/debug+', '/debug:full']
|
||||
else:
|
||||
val = ['/debug-']
|
||||
self.env.append_value('CSFLAGS', val)
|
||||
|
||||
|
||||
class mcs(Task.Task):
|
||||
"""
|
||||
Compile C# files
|
||||
"""
|
||||
color = 'YELLOW'
|
||||
run_str = '${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'
|
||||
|
||||
def exec_command(self, cmd, **kw):
|
||||
bld = self.generator.bld
|
||||
|
||||
try:
|
||||
if not kw.get('cwd', None):
|
||||
kw['cwd'] = bld.cwd
|
||||
except AttributeError:
|
||||
bld.cwd = kw['cwd'] = bld.variant_dir
|
||||
|
||||
try:
|
||||
tmp = None
|
||||
if isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:
|
||||
program = cmd[0] #unquoted program name, otherwise exec_command will fail
|
||||
cmd = [self.quote_response_command(x) for x in cmd]
|
||||
(fd, tmp) = tempfile.mkstemp()
|
||||
os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())
|
||||
os.close(fd)
|
||||
cmd = [program, '@' + tmp]
|
||||
# no return here, that's on purpose
|
||||
ret = self.generator.bld.exec_command(cmd, **kw)
|
||||
finally:
|
||||
if tmp:
|
||||
try:
|
||||
os.remove(tmp)
|
||||
except OSError:
|
||||
pass # anti-virus and indexers can keep the files open -_-
|
||||
return ret
|
||||
|
||||
def quote_response_command(self, flag):
|
||||
# /noconfig is not allowed when using response files
|
||||
if flag.lower() == '/noconfig':
|
||||
return ''
|
||||
|
||||
if flag.find(' ') > -1:
|
||||
for x in ('/r:', '/reference:', '/resource:', '/lib:', '/out:'):
|
||||
if flag.startswith(x):
|
||||
flag = '%s"%s"' % (x, flag[len(x):])
|
||||
break
|
||||
else:
|
||||
flag = '"%s"' % flag
|
||||
return flag
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Find a C# compiler, set the variable MCS for the compiler and CS_NAME (mono or csc)
|
||||
"""
|
||||
csc = getattr(Options.options, 'cscbinary', None)
|
||||
if csc:
|
||||
conf.env.MCS = csc
|
||||
conf.find_program(['csc', 'mcs', 'gmcs'], var='MCS')
|
||||
conf.env.ASS_ST = '/r:%s'
|
||||
conf.env.RES_ST = '/resource:%s'
|
||||
|
||||
conf.env.CS_NAME = 'csc'
|
||||
if str(conf.env.MCS).lower().find('mcs') > -1:
|
||||
conf.env.CS_NAME = 'mono'
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add a command-line option for the configuration::
|
||||
|
||||
$ waf configure --with-csc-binary=/foo/bar/mcs
|
||||
"""
|
||||
opt.add_option('--with-csc-binary', type='string', dest='cscbinary')
|
||||
|
||||
class fake_csshlib(Task.Task):
|
||||
"""
|
||||
Task used for reading a foreign .net assembly and adding the dependency on it
|
||||
"""
|
||||
color = 'YELLOW'
|
||||
inst_to = None
|
||||
|
||||
def runnable_status(self):
|
||||
for x in self.outputs:
|
||||
x.sig = Utils.h_file(x.abspath())
|
||||
return Task.SKIP_ME
|
||||
|
||||
@conf
|
||||
def read_csshlib(self, name, paths=[]):
|
||||
"""
|
||||
Read a foreign .net assembly for the *use* system::
|
||||
|
||||
def build(bld):
|
||||
bld.read_csshlib('ManagedLibrary.dll', paths=[bld.env.mylibrarypath])
|
||||
bld(features='cs', source='Hi.cs', bintype='exe', gen='hi.exe', use='ManagedLibrary.dll')
|
||||
|
||||
:param name: Name of the library
|
||||
:type name: string
|
||||
:param paths: Folders in which the library may be found
|
||||
:type paths: list of string
|
||||
:return: A task generator having the feature *fake_lib* which will call :py:func:`waflib.Tools.ccroot.process_lib`
|
||||
:rtype: :py:class:`waflib.TaskGen.task_gen`
|
||||
"""
|
||||
return self(name=name, features='fake_lib', lib_paths=paths, lib_type='csshlib')
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"Base for c++ programs and libraries"
|
||||
|
||||
from waflib import TaskGen, Task, Utils
|
||||
from waflib.Tools import c_preproc
|
||||
from waflib.Tools.ccroot import link_task, stlink_task
|
||||
|
||||
@TaskGen.extension('.cpp','.cc','.cxx','.C','.c++')
|
||||
def cxx_hook(self, node):
|
||||
"Bind the c++ file extensions to the creation of a :py:class:`waflib.Tools.cxx.cxx` instance"
|
||||
return self.create_compiled_task('cxx', node)
|
||||
|
||||
if not '.c' in TaskGen.task_gen.mappings:
|
||||
TaskGen.task_gen.mappings['.c'] = TaskGen.task_gen.mappings['.cpp']
|
||||
|
||||
class cxx(Task.Task):
|
||||
"Compile C++ files into object files"
|
||||
run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}'
|
||||
vars = ['CXXDEPS'] # unused variable to depend on, just in case
|
||||
ext_in = ['.h'] # set the build order easily by using ext_out=['.h']
|
||||
scan = c_preproc.scan
|
||||
|
||||
class cxxprogram(link_task):
|
||||
"Link object files into a c++ program"
|
||||
run_str = '${LINK_CXX} ${LINKFLAGS} ${CXXLNK_SRC_F}${SRC} ${CXXLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'
|
||||
vars = ['LINKDEPS']
|
||||
ext_out = ['.bin']
|
||||
inst_to = '${BINDIR}'
|
||||
|
||||
class cxxshlib(cxxprogram):
|
||||
"Link object files into a c++ shared library"
|
||||
inst_to = '${LIBDIR}'
|
||||
|
||||
class cxxstlib(stlink_task):
|
||||
"Link object files into a c++ static library"
|
||||
pass # do not remove
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Carlos Rafael Giani, 2007 (dv)
|
||||
# Thomas Nagy, 2007-2010 (ita)
|
||||
|
||||
from waflib import Utils, Task, Errors
|
||||
from waflib.TaskGen import taskgen_method, feature, extension
|
||||
from waflib.Tools import d_scan, d_config
|
||||
from waflib.Tools.ccroot import link_task, stlink_task
|
||||
|
||||
class d(Task.Task):
|
||||
"Compile a d file into an object file"
|
||||
color = 'GREEN'
|
||||
run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_SRC_F:SRC} ${D_TGT_F:TGT}'
|
||||
scan = d_scan.scan
|
||||
|
||||
class d_with_header(d):
|
||||
"Compile a d file and generate a header"
|
||||
run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_HDR_F:tgt.outputs[1].bldpath()} ${D_SRC_F:SRC} ${D_TGT_F:tgt.outputs[0].bldpath()}'
|
||||
|
||||
class d_header(Task.Task):
|
||||
"Compile d headers"
|
||||
color = 'BLUE'
|
||||
run_str = '${D} ${D_HEADER} ${SRC}'
|
||||
|
||||
class dprogram(link_task):
|
||||
"Link object files into a d program"
|
||||
run_str = '${D_LINKER} ${LINKFLAGS} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F:TGT} ${RPATH_ST:RPATH} ${DSTLIB_MARKER} ${DSTLIBPATH_ST:STLIBPATH} ${DSTLIB_ST:STLIB} ${DSHLIB_MARKER} ${DLIBPATH_ST:LIBPATH} ${DSHLIB_ST:LIB}'
|
||||
inst_to = '${BINDIR}'
|
||||
|
||||
class dshlib(dprogram):
|
||||
"Link object files into a d shared library"
|
||||
inst_to = '${LIBDIR}'
|
||||
|
||||
class dstlib(stlink_task):
|
||||
"Link object files into a d static library"
|
||||
pass # do not remove
|
||||
|
||||
@extension('.d', '.di', '.D')
|
||||
def d_hook(self, node):
|
||||
"""
|
||||
Compile *D* files. To get .di files as well as .o files, set the following::
|
||||
|
||||
def build(bld):
|
||||
bld.program(source='foo.d', target='app', generate_headers=True)
|
||||
|
||||
"""
|
||||
ext = Utils.destos_to_binfmt(self.env.DEST_OS) == 'pe' and 'obj' or 'o'
|
||||
out = '%s.%d.%s' % (node.name, self.idx, ext)
|
||||
def create_compiled_task(self, name, node):
|
||||
task = self.create_task(name, node, node.parent.find_or_declare(out))
|
||||
try:
|
||||
self.compiled_tasks.append(task)
|
||||
except AttributeError:
|
||||
self.compiled_tasks = [task]
|
||||
return task
|
||||
|
||||
if getattr(self, 'generate_headers', None):
|
||||
tsk = create_compiled_task(self, 'd_with_header', node)
|
||||
tsk.outputs.append(node.change_ext(self.env['DHEADER_ext']))
|
||||
else:
|
||||
tsk = create_compiled_task(self, 'd', node)
|
||||
return tsk
|
||||
|
||||
@taskgen_method
|
||||
def generate_header(self, filename):
|
||||
"""
|
||||
See feature request #104::
|
||||
|
||||
def build(bld):
|
||||
tg = bld.program(source='foo.d', target='app')
|
||||
tg.generate_header('blah.d')
|
||||
# is equivalent to:
|
||||
#tg = bld.program(source='foo.d', target='app', header_lst='blah.d')
|
||||
|
||||
:param filename: header to create
|
||||
:type filename: string
|
||||
"""
|
||||
try:
|
||||
self.header_lst.append([filename, self.install_path])
|
||||
except AttributeError:
|
||||
self.header_lst = [[filename, self.install_path]]
|
||||
|
||||
@feature('d')
|
||||
def process_header(self):
|
||||
"""
|
||||
Process the attribute 'header_lst' to create the d header compilation tasks::
|
||||
|
||||
def build(bld):
|
||||
bld.program(source='foo.d', target='app', header_lst='blah.d')
|
||||
"""
|
||||
for i in getattr(self, 'header_lst', []):
|
||||
node = self.path.find_resource(i[0])
|
||||
if not node:
|
||||
raise Errors.WafError('file %r not found on d obj' % i[0])
|
||||
self.create_task('d_header', node, node.change_ext('.di'))
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
from waflib import Utils
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def d_platform_flags(self):
|
||||
"""
|
||||
Set the extensions dll/so for d programs and libraries
|
||||
"""
|
||||
v = self.env
|
||||
if not v.DEST_OS:
|
||||
v.DEST_OS = Utils.unversioned_sys_platform()
|
||||
binfmt = Utils.destos_to_binfmt(self.env.DEST_OS)
|
||||
if binfmt == 'pe':
|
||||
v['dprogram_PATTERN'] = '%s.exe'
|
||||
v['dshlib_PATTERN'] = 'lib%s.dll'
|
||||
v['dstlib_PATTERN'] = 'lib%s.a'
|
||||
elif binfmt == 'mac-o':
|
||||
v['dprogram_PATTERN'] = '%s'
|
||||
v['dshlib_PATTERN'] = 'lib%s.dylib'
|
||||
v['dstlib_PATTERN'] = 'lib%s.a'
|
||||
else:
|
||||
v['dprogram_PATTERN'] = '%s'
|
||||
v['dshlib_PATTERN'] = 'lib%s.so'
|
||||
v['dstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
DLIB = '''
|
||||
version(D_Version2) {
|
||||
import std.stdio;
|
||||
int main() {
|
||||
writefln("phobos2");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
version(Tango) {
|
||||
import tango.stdc.stdio;
|
||||
int main() {
|
||||
printf("tango");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
import std.stdio;
|
||||
int main() {
|
||||
writefln("phobos1");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
"""Detection string for the D standard library"""
|
||||
|
||||
@conf
|
||||
def check_dlibrary(self, execute=True):
|
||||
"""
|
||||
Detect the kind of standard library that comes with the compiler, will set conf.env.DLIBRARY to tango, phobos1 or phobos2.
|
||||
"""
|
||||
ret = self.check_cc(features='d dprogram', fragment=DLIB, compile_filename='test.d', execute=execute, define_ret=True)
|
||||
if execute:
|
||||
self.env.DLIBRARY = ret.strip()
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
"""
|
||||
Provide a scanner for finding dependencies on d files
|
||||
"""
|
||||
|
||||
import re
|
||||
from waflib import Utils, Logs
|
||||
|
||||
def filter_comments(filename):
|
||||
"""
|
||||
:param filename: d file name
|
||||
:type filename: string
|
||||
:rtype: list
|
||||
:return: a list of characters
|
||||
"""
|
||||
txt = Utils.readf(filename)
|
||||
i = 0
|
||||
buf = []
|
||||
max = len(txt)
|
||||
begin = 0
|
||||
while i < max:
|
||||
c = txt[i]
|
||||
if c == '"' or c == "'": # skip a string or character literal
|
||||
buf.append(txt[begin:i])
|
||||
delim = c
|
||||
i += 1
|
||||
while i < max:
|
||||
c = txt[i]
|
||||
if c == delim: break
|
||||
elif c == '\\': # skip the character following backslash
|
||||
i += 1
|
||||
i += 1
|
||||
i += 1
|
||||
begin = i
|
||||
elif c == '/': # try to replace a comment with whitespace
|
||||
buf.append(txt[begin:i])
|
||||
i += 1
|
||||
if i == max: break
|
||||
c = txt[i]
|
||||
if c == '+': # eat nesting /+ +/ comment
|
||||
i += 1
|
||||
nesting = 1
|
||||
c = None
|
||||
while i < max:
|
||||
prev = c
|
||||
c = txt[i]
|
||||
if prev == '/' and c == '+':
|
||||
nesting += 1
|
||||
c = None
|
||||
elif prev == '+' and c == '/':
|
||||
nesting -= 1
|
||||
if nesting == 0: break
|
||||
c = None
|
||||
i += 1
|
||||
elif c == '*': # eat /* */ comment
|
||||
i += 1
|
||||
c = None
|
||||
while i < max:
|
||||
prev = c
|
||||
c = txt[i]
|
||||
if prev == '*' and c == '/': break
|
||||
i += 1
|
||||
elif c == '/': # eat // comment
|
||||
i += 1
|
||||
while i < max and txt[i] != '\n':
|
||||
i += 1
|
||||
else: # no comment
|
||||
begin = i - 1
|
||||
continue
|
||||
i += 1
|
||||
begin = i
|
||||
buf.append(' ')
|
||||
else:
|
||||
i += 1
|
||||
buf.append(txt[begin:])
|
||||
return buf
|
||||
|
||||
class d_parser(object):
|
||||
"""
|
||||
Parser for d files
|
||||
"""
|
||||
def __init__(self, env, incpaths):
|
||||
#self.code = ''
|
||||
#self.module = ''
|
||||
#self.imports = []
|
||||
|
||||
self.allnames = []
|
||||
|
||||
self.re_module = re.compile("module\s+([^;]+)")
|
||||
self.re_import = re.compile("import\s+([^;]+)")
|
||||
self.re_import_bindings = re.compile("([^:]+):(.*)")
|
||||
self.re_import_alias = re.compile("[^=]+=(.+)")
|
||||
|
||||
self.env = env
|
||||
|
||||
self.nodes = []
|
||||
self.names = []
|
||||
|
||||
self.incpaths = incpaths
|
||||
|
||||
def tryfind(self, filename):
|
||||
"""
|
||||
Search file a file matching an module/import directive
|
||||
|
||||
:param filename: file to read
|
||||
:type filename: string
|
||||
"""
|
||||
found = 0
|
||||
for n in self.incpaths:
|
||||
found = n.find_resource(filename.replace('.', '/') + '.d')
|
||||
if found:
|
||||
self.nodes.append(found)
|
||||
self.waiting.append(found)
|
||||
break
|
||||
if not found:
|
||||
if not filename in self.names:
|
||||
self.names.append(filename)
|
||||
|
||||
def get_strings(self, code):
|
||||
"""
|
||||
:param code: d code to parse
|
||||
:type code: string
|
||||
:return: the modules that the code uses
|
||||
:rtype: a list of match objects
|
||||
"""
|
||||
#self.imports = []
|
||||
self.module = ''
|
||||
lst = []
|
||||
|
||||
# get the module name (if present)
|
||||
|
||||
mod_name = self.re_module.search(code)
|
||||
if mod_name:
|
||||
self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces
|
||||
|
||||
# go through the code, have a look at all import occurrences
|
||||
|
||||
# first, lets look at anything beginning with "import" and ending with ";"
|
||||
import_iterator = self.re_import.finditer(code)
|
||||
if import_iterator:
|
||||
for import_match in import_iterator:
|
||||
import_match_str = re.sub('\s+', '', import_match.group(1)) # strip all whitespaces
|
||||
|
||||
# does this end with an import bindings declaration?
|
||||
# (import bindings always terminate the list of imports)
|
||||
bindings_match = self.re_import_bindings.match(import_match_str)
|
||||
if bindings_match:
|
||||
import_match_str = bindings_match.group(1)
|
||||
# if so, extract the part before the ":" (since the module declaration(s) is/are located there)
|
||||
|
||||
# split the matching string into a bunch of strings, separated by a comma
|
||||
matches = import_match_str.split(',')
|
||||
|
||||
for match in matches:
|
||||
alias_match = self.re_import_alias.match(match)
|
||||
if alias_match:
|
||||
# is this an alias declaration? (alias = module name) if so, extract the module name
|
||||
match = alias_match.group(1)
|
||||
|
||||
lst.append(match)
|
||||
return lst
|
||||
|
||||
def start(self, node):
|
||||
"""
|
||||
The parsing starts here
|
||||
|
||||
:param node: input file
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
self.waiting = [node]
|
||||
# while the stack is not empty, add the dependencies
|
||||
while self.waiting:
|
||||
nd = self.waiting.pop(0)
|
||||
self.iter(nd)
|
||||
|
||||
def iter(self, node):
|
||||
"""
|
||||
Find all the modules that a file depends on, uses :py:meth:`waflib.Tools.d_scan.d_parser.tryfind` to process dependent files
|
||||
|
||||
:param node: input file
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
path = node.abspath() # obtain the absolute path
|
||||
code = "".join(filter_comments(path)) # read the file and filter the comments
|
||||
names = self.get_strings(code) # obtain the import strings
|
||||
for x in names:
|
||||
# optimization
|
||||
if x in self.allnames: continue
|
||||
self.allnames.append(x)
|
||||
|
||||
# for each name, see if it is like a node or not
|
||||
self.tryfind(x)
|
||||
|
||||
def scan(self):
|
||||
"look for .d/.di used by a d file"
|
||||
env = self.env
|
||||
gruik = d_parser(env, self.generator.includes_nodes)
|
||||
node = self.inputs[0]
|
||||
gruik.start(node)
|
||||
nodes = gruik.nodes
|
||||
names = gruik.names
|
||||
|
||||
if Logs.verbose:
|
||||
Logs.debug('deps: deps for %s: %r; unresolved %r' % (str(node), nodes, names))
|
||||
return (nodes, names)
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Ali Sabil, 2007
|
||||
|
||||
"""
|
||||
Compile dbus files with **dbus-binding-tool**
|
||||
|
||||
Typical usage::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c dbus')
|
||||
def configure(conf):
|
||||
conf.load('compiler_c dbus')
|
||||
def build(bld):
|
||||
tg = bld.program(
|
||||
includes = '.',
|
||||
source = bld.path.ant_glob('*.c'),
|
||||
target = 'gnome-hello')
|
||||
tg.add_dbus_file('test.xml', 'test_prefix', 'glib-server')
|
||||
"""
|
||||
|
||||
from waflib import Task, Errors
|
||||
from waflib.TaskGen import taskgen_method, before_method
|
||||
|
||||
@taskgen_method
|
||||
def add_dbus_file(self, filename, prefix, mode):
|
||||
"""
|
||||
Add a dbus file to the list of dbus files to process. Store them in the attribute *dbus_lst*.
|
||||
|
||||
:param filename: xml file to compile
|
||||
:type filename: string
|
||||
:param prefix: dbus binding tool prefix (--prefix=prefix)
|
||||
:type prefix: string
|
||||
:param mode: dbus binding tool mode (--mode=mode)
|
||||
:type mode: string
|
||||
"""
|
||||
if not hasattr(self, 'dbus_lst'):
|
||||
self.dbus_lst = []
|
||||
if not 'process_dbus' in self.meths:
|
||||
self.meths.append('process_dbus')
|
||||
self.dbus_lst.append([filename, prefix, mode])
|
||||
|
||||
@before_method('apply_core')
|
||||
def process_dbus(self):
|
||||
"""
|
||||
Process the dbus files stored in the attribute *dbus_lst* to create :py:class:`waflib.Tools.dbus.dbus_binding_tool` instances.
|
||||
"""
|
||||
for filename, prefix, mode in getattr(self, 'dbus_lst', []):
|
||||
node = self.path.find_resource(filename)
|
||||
if not node:
|
||||
raise Errors.WafError('file not found ' + filename)
|
||||
tsk = self.create_task('dbus_binding_tool', node, node.change_ext('.h'))
|
||||
tsk.env.DBUS_BINDING_TOOL_PREFIX = prefix
|
||||
tsk.env.DBUS_BINDING_TOOL_MODE = mode
|
||||
|
||||
class dbus_binding_tool(Task.Task):
|
||||
"""
|
||||
Compile a dbus file
|
||||
"""
|
||||
color = 'BLUE'
|
||||
ext_out = ['.h']
|
||||
run_str = '${DBUS_BINDING_TOOL} --prefix=${DBUS_BINDING_TOOL_PREFIX} --mode=${DBUS_BINDING_TOOL_MODE} --output=${TGT} ${SRC}'
|
||||
shell = True # temporary workaround for #795
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the program dbus-binding-tool and set the *conf.env.DBUS_BINDING_TOOL*
|
||||
"""
|
||||
dbus_binding_tool = conf.find_program('dbus-binding-tool', var='DBUS_BINDING_TOOL')
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Carlos Rafael Giani, 2007 (dv)
|
||||
# Thomas Nagy, 2008-2010 (ita)
|
||||
|
||||
import sys
|
||||
from waflib.Tools import ar, d
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_dmd(conf):
|
||||
"""
|
||||
Find the program *dmd*, *dmd2*, or *ldc* and set the variable *D*
|
||||
"""
|
||||
conf.find_program(['dmd', 'dmd2', 'ldc'], var='D')
|
||||
|
||||
# make sure that we're dealing with dmd1, dmd2, or ldc(1)
|
||||
out = conf.cmd_and_log([conf.env.D, '--help'])
|
||||
if out.find("D Compiler v") == -1:
|
||||
out = conf.cmd_and_log([conf.env.D, '-version'])
|
||||
if out.find("based on DMD v1.") == -1:
|
||||
conf.fatal("detected compiler is not dmd/ldc")
|
||||
|
||||
@conf
|
||||
def common_flags_ldc(conf):
|
||||
"""
|
||||
Set the D flags required by *ldc*
|
||||
"""
|
||||
v = conf.env
|
||||
v['DFLAGS'] = ['-d-version=Posix']
|
||||
v['LINKFLAGS'] = []
|
||||
v['DFLAGS_dshlib'] = ['-relocation-model=pic']
|
||||
|
||||
@conf
|
||||
def common_flags_dmd(conf):
|
||||
"""
|
||||
Set the flags required by *dmd* or *dmd2*
|
||||
"""
|
||||
|
||||
v = conf.env
|
||||
|
||||
# _DFLAGS _DIMPORTFLAGS
|
||||
|
||||
# Compiler is dmd so 'gdc' part will be ignored, just
|
||||
# ensure key is there, so wscript can append flags to it
|
||||
#v['DFLAGS'] = ['-version=Posix']
|
||||
|
||||
v['D_SRC_F'] = ['-c']
|
||||
v['D_TGT_F'] = '-of%s'
|
||||
|
||||
# linker
|
||||
v['D_LINKER'] = v['D']
|
||||
v['DLNK_SRC_F'] = ''
|
||||
v['DLNK_TGT_F'] = '-of%s'
|
||||
v['DINC_ST'] = '-I%s'
|
||||
|
||||
v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''
|
||||
v['DSTLIB_ST'] = v['DSHLIB_ST'] = '-L-l%s'
|
||||
v['DSTLIBPATH_ST'] = v['DLIBPATH_ST'] = '-L-L%s'
|
||||
|
||||
v['LINKFLAGS_dprogram']= ['-quiet']
|
||||
|
||||
v['DFLAGS_dshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_dshlib'] = ['-L-shared']
|
||||
|
||||
v['DHEADER_ext'] = '.di'
|
||||
v.DFLAGS_d_with_header = ['-H', '-Hf']
|
||||
v['D_HDR_F'] = '%s'
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Configuration for *dmd*, *dmd2*, and *ldc*
|
||||
"""
|
||||
conf.find_dmd()
|
||||
|
||||
if sys.platform == 'win32':
|
||||
out = conf.cmd_and_log([conf.env.D, '--help'])
|
||||
if out.find("D Compiler v2.") > -1:
|
||||
conf.fatal('dmd2 on Windows is not supported, use gdc or ldc2 instead')
|
||||
|
||||
conf.load('ar')
|
||||
conf.load('d')
|
||||
conf.common_flags_dmd()
|
||||
conf.d_platform_flags()
|
||||
|
||||
if str(conf.env.D).find('ldc') > -1:
|
||||
conf.common_flags_ldc()
|
||||
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2011 (ita)
|
||||
|
||||
"""
|
||||
errcheck: highlight common mistakes
|
||||
|
||||
There is a performance hit, so this tool is only loaded when running "waf -v"
|
||||
"""
|
||||
|
||||
typos = {
|
||||
'feature':'features',
|
||||
'sources':'source',
|
||||
'targets':'target',
|
||||
'include':'includes',
|
||||
'export_include':'export_includes',
|
||||
'define':'defines',
|
||||
'importpath':'includes',
|
||||
'installpath':'install_path',
|
||||
'iscopy':'is_copy',
|
||||
}
|
||||
|
||||
meths_typos = ['__call__', 'program', 'shlib', 'stlib', 'objects']
|
||||
|
||||
from waflib import Logs, Build, Node, Task, TaskGen, ConfigSet, Errors, Utils
|
||||
import waflib.Tools.ccroot
|
||||
|
||||
def check_same_targets(self):
|
||||
mp = Utils.defaultdict(list)
|
||||
uids = {}
|
||||
|
||||
def check_task(tsk):
|
||||
if not isinstance(tsk, Task.Task):
|
||||
return
|
||||
|
||||
for node in tsk.outputs:
|
||||
mp[node].append(tsk)
|
||||
try:
|
||||
uids[tsk.uid()].append(tsk)
|
||||
except KeyError:
|
||||
uids[tsk.uid()] = [tsk]
|
||||
|
||||
for g in self.groups:
|
||||
for tg in g:
|
||||
try:
|
||||
for tsk in tg.tasks:
|
||||
check_task(tsk)
|
||||
except AttributeError:
|
||||
# raised if not a task generator, which should be uncommon
|
||||
check_task(tg)
|
||||
|
||||
dupe = False
|
||||
for (k, v) in mp.items():
|
||||
if len(v) > 1:
|
||||
dupe = True
|
||||
msg = '* Node %r is created more than once%s. The task generators are:' % (k, Logs.verbose == 1 and " (full message on 'waf -v -v')" or "")
|
||||
Logs.error(msg)
|
||||
for x in v:
|
||||
if Logs.verbose > 1:
|
||||
Logs.error(' %d. %r' % (1 + v.index(x), x.generator))
|
||||
else:
|
||||
Logs.error(' %d. %r in %r' % (1 + v.index(x), x.generator.name, getattr(x.generator, 'path', None)))
|
||||
|
||||
if not dupe:
|
||||
for (k, v) in uids.items():
|
||||
if len(v) > 1:
|
||||
Logs.error('* Several tasks use the same identifier. Please check the information on\n http://docs.waf.googlecode.com/git/apidocs_16/Task.html#waflib.Task.Task.uid')
|
||||
for tsk in v:
|
||||
Logs.error(' - object %r (%r) defined in %r' % (tsk.__class__.__name__, tsk, tsk.generator))
|
||||
|
||||
def check_invalid_constraints(self):
|
||||
feat = set([])
|
||||
for x in list(TaskGen.feats.values()):
|
||||
feat.union(set(x))
|
||||
for (x, y) in TaskGen.task_gen.prec.items():
|
||||
feat.add(x)
|
||||
feat.union(set(y))
|
||||
ext = set([])
|
||||
for x in TaskGen.task_gen.mappings.values():
|
||||
ext.add(x.__name__)
|
||||
invalid = ext & feat
|
||||
if invalid:
|
||||
Logs.error('The methods %r have invalid annotations: @extension <-> @feature/@before_method/@after_method' % list(invalid))
|
||||
|
||||
# the build scripts have been read, so we can check for invalid after/before attributes on task classes
|
||||
for cls in list(Task.classes.values()):
|
||||
for x in ('before', 'after'):
|
||||
for y in Utils.to_list(getattr(cls, x, [])):
|
||||
if not Task.classes.get(y, None):
|
||||
Logs.error('Erroneous order constraint %r=%r on task class %r' % (x, y, cls.__name__))
|
||||
if getattr(cls, 'rule', None):
|
||||
Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")' % cls.__name__)
|
||||
|
||||
def replace(m):
|
||||
"""
|
||||
We could add properties, but they would not work in some cases:
|
||||
bld.program(...) requires 'source' in the attributes
|
||||
"""
|
||||
oldcall = getattr(Build.BuildContext, m)
|
||||
def call(self, *k, **kw):
|
||||
ret = oldcall(self, *k, **kw)
|
||||
for x in typos:
|
||||
if x in kw:
|
||||
if x == 'iscopy' and 'subst' in getattr(self, 'features', ''):
|
||||
continue
|
||||
err = True
|
||||
Logs.error('Fix the typo %r -> %r on %r' % (x, typos[x], ret))
|
||||
return ret
|
||||
setattr(Build.BuildContext, m, call)
|
||||
|
||||
def enhance_lib():
|
||||
"""
|
||||
modify existing classes and methods
|
||||
"""
|
||||
for m in meths_typos:
|
||||
replace(m)
|
||||
|
||||
# catch '..' in ant_glob patterns
|
||||
def ant_glob(self, *k, **kw):
|
||||
if k:
|
||||
lst=Utils.to_list(k[0])
|
||||
for pat in lst:
|
||||
if '..' in pat.split('/'):
|
||||
Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'" % k[0])
|
||||
if kw.get('remove', True):
|
||||
try:
|
||||
if self.is_child_of(self.ctx.bldnode) and not kw.get('quiet', False):
|
||||
Logs.error('Using ant_glob on the build folder (%r) is dangerous (quiet=True to disable this warning)' % self)
|
||||
except AttributeError:
|
||||
pass
|
||||
return self.old_ant_glob(*k, **kw)
|
||||
Node.Node.old_ant_glob = Node.Node.ant_glob
|
||||
Node.Node.ant_glob = ant_glob
|
||||
|
||||
# catch conflicting ext_in/ext_out/before/after declarations
|
||||
old = Task.is_before
|
||||
def is_before(t1, t2):
|
||||
ret = old(t1, t2)
|
||||
if ret and old(t2, t1):
|
||||
Logs.error('Contradictory order constraints in classes %r %r' % (t1, t2))
|
||||
return ret
|
||||
Task.is_before = is_before
|
||||
|
||||
# check for bld(feature='cshlib') where no 'c' is given - this can be either a mistake or on purpose
|
||||
# so we only issue a warning
|
||||
def check_err_features(self):
|
||||
lst = self.to_list(self.features)
|
||||
if 'shlib' in lst:
|
||||
Logs.error('feature shlib -> cshlib, dshlib or cxxshlib')
|
||||
for x in ('c', 'cxx', 'd', 'fc'):
|
||||
if not x in lst and lst and lst[0] in [x+y for y in ('program', 'shlib', 'stlib')]:
|
||||
Logs.error('%r features is probably missing %r' % (self, x))
|
||||
TaskGen.feature('*')(check_err_features)
|
||||
|
||||
# check for erroneous order constraints
|
||||
def check_err_order(self):
|
||||
if not hasattr(self, 'rule') and not 'subst' in Utils.to_list(self.features):
|
||||
for x in ('before', 'after', 'ext_in', 'ext_out'):
|
||||
if hasattr(self, x):
|
||||
Logs.warn('Erroneous order constraint %r on non-rule based task generator %r' % (x, self))
|
||||
else:
|
||||
for x in ('before', 'after'):
|
||||
for y in self.to_list(getattr(self, x, [])):
|
||||
if not Task.classes.get(y, None):
|
||||
Logs.error('Erroneous order constraint %s=%r on %r (no such class)' % (x, y, self))
|
||||
TaskGen.feature('*')(check_err_order)
|
||||
|
||||
# check for @extension used with @feature/@before_method/@after_method
|
||||
def check_compile(self):
|
||||
check_invalid_constraints(self)
|
||||
try:
|
||||
ret = self.orig_compile()
|
||||
finally:
|
||||
check_same_targets(self)
|
||||
return ret
|
||||
Build.BuildContext.orig_compile = Build.BuildContext.compile
|
||||
Build.BuildContext.compile = check_compile
|
||||
|
||||
# check for invalid build groups #914
|
||||
def use_rec(self, name, **kw):
|
||||
try:
|
||||
y = self.bld.get_tgen_by_name(name)
|
||||
except Errors.WafError:
|
||||
pass
|
||||
else:
|
||||
idx = self.bld.get_group_idx(self)
|
||||
odx = self.bld.get_group_idx(y)
|
||||
if odx > idx:
|
||||
msg = "Invalid 'use' across build groups:"
|
||||
if Logs.verbose > 1:
|
||||
msg += '\n target %r\n uses:\n %r' % (self, y)
|
||||
else:
|
||||
msg += " %r uses %r (try 'waf -v -v' for the full error)" % (self.name, name)
|
||||
raise Errors.WafError(msg)
|
||||
self.orig_use_rec(name, **kw)
|
||||
TaskGen.task_gen.orig_use_rec = TaskGen.task_gen.use_rec
|
||||
TaskGen.task_gen.use_rec = use_rec
|
||||
|
||||
# check for env.append
|
||||
def getattri(self, name, default=None):
|
||||
if name == 'append' or name == 'add':
|
||||
raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique')
|
||||
elif name == 'prepend':
|
||||
raise Errors.WafError('env.prepend does not exist: use env.prepend_value')
|
||||
if name in self.__slots__:
|
||||
return object.__getattr__(self, name, default)
|
||||
else:
|
||||
return self[name]
|
||||
ConfigSet.ConfigSet.__getattr__ = getattri
|
||||
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add a few methods
|
||||
"""
|
||||
enhance_lib()
|
||||
|
||||
def configure(conf):
|
||||
pass
|
||||
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# DC 2008
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
"""
|
||||
fortran support
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from waflib import Utils, Task, TaskGen, Logs
|
||||
from waflib.Tools import ccroot, fc_config, fc_scan
|
||||
from waflib.TaskGen import feature, before_method, after_method, extension
|
||||
from waflib.Configure import conf
|
||||
|
||||
ccroot.USELIB_VARS['fc'] = set(['FCFLAGS', 'DEFINES', 'INCLUDES'])
|
||||
ccroot.USELIB_VARS['fcprogram_test'] = ccroot.USELIB_VARS['fcprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
|
||||
ccroot.USELIB_VARS['fcshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
|
||||
ccroot.USELIB_VARS['fcstlib'] = set(['ARFLAGS', 'LINKDEPS'])
|
||||
|
||||
@feature('fcprogram', 'fcshlib', 'fcstlib', 'fcprogram_test')
|
||||
def dummy(self):
|
||||
pass
|
||||
|
||||
@extension('.f', '.f90', '.F', '.F90', '.for', '.FOR')
|
||||
def fc_hook(self, node):
|
||||
"Bind the typical Fortran file extensions to the creation of a :py:class:`waflib.Tools.fc.fc` instance"
|
||||
return self.create_compiled_task('fc', node)
|
||||
|
||||
@conf
|
||||
def modfile(conf, name):
|
||||
"""
|
||||
Turn a module name into the right module file name.
|
||||
Defaults to all lower case.
|
||||
"""
|
||||
return {'lower' :name.lower() + '.mod',
|
||||
'lower.MOD' :name.upper() + '.MOD',
|
||||
'UPPER.mod' :name.upper() + '.mod',
|
||||
'UPPER' :name.upper() + '.MOD'}[conf.env.FC_MOD_CAPITALIZATION or 'lower']
|
||||
|
||||
def get_fortran_tasks(tsk):
|
||||
"""
|
||||
Obtain all other fortran tasks from the same build group. Those tasks must not have
|
||||
the attribute 'nomod' or 'mod_fortran_done'
|
||||
"""
|
||||
bld = tsk.generator.bld
|
||||
tasks = bld.get_tasks_group(bld.get_group_idx(tsk.generator))
|
||||
return [x for x in tasks if isinstance(x, fc) and not getattr(x, 'nomod', None) and not getattr(x, 'mod_fortran_done', None)]
|
||||
|
||||
class fc(Task.Task):
|
||||
"""
|
||||
The fortran tasks can only run when all fortran tasks in the current group are ready to be executed
|
||||
This may cause a deadlock if another fortran task is waiting for something that cannot happen (circular dependency)
|
||||
in this case, set the 'nomod=True' on those tasks instances to break the loop
|
||||
"""
|
||||
|
||||
color = 'GREEN'
|
||||
run_str = '${FC} ${FCFLAGS} ${FCINCPATH_ST:INCPATHS} ${FCDEFINES_ST:DEFINES} ${_FCMODOUTFLAGS} ${FC_TGT_F}${TGT[0].abspath()} ${FC_SRC_F}${SRC[0].abspath()}'
|
||||
vars = ["FORTRANMODPATHFLAG"]
|
||||
|
||||
def scan(self):
|
||||
"""scanner for fortran dependencies"""
|
||||
tmp = fc_scan.fortran_parser(self.generator.includes_nodes)
|
||||
tmp.task = self
|
||||
tmp.start(self.inputs[0])
|
||||
if Logs.verbose:
|
||||
Logs.debug('deps: deps for %r: %r; unresolved %r' % (self.inputs, tmp.nodes, tmp.names))
|
||||
return (tmp.nodes, tmp.names)
|
||||
|
||||
def runnable_status(self):
|
||||
"""
|
||||
Set the mod file outputs and the dependencies on the mod files over all the fortran tasks
|
||||
executed by the main thread so there are no concurrency issues
|
||||
"""
|
||||
if getattr(self, 'mod_fortran_done', None):
|
||||
return super(fc, self).runnable_status()
|
||||
|
||||
# now, if we reach this part it is because this fortran task is the first in the list
|
||||
bld = self.generator.bld
|
||||
|
||||
# obtain the fortran tasks
|
||||
lst = get_fortran_tasks(self)
|
||||
|
||||
# disable this method for other tasks
|
||||
for tsk in lst:
|
||||
tsk.mod_fortran_done = True
|
||||
|
||||
# wait for all the .f tasks to be ready for execution
|
||||
# and ensure that the scanners are called at least once
|
||||
for tsk in lst:
|
||||
ret = tsk.runnable_status()
|
||||
if ret == Task.ASK_LATER:
|
||||
# we have to wait for one of the other fortran tasks to be ready
|
||||
# this may deadlock if there are dependencies between the fortran tasks
|
||||
# but this should not happen (we are setting them here!)
|
||||
for x in lst:
|
||||
x.mod_fortran_done = None
|
||||
|
||||
# TODO sort the list of tasks in bld.producer.outstanding to put all fortran tasks at the end
|
||||
return Task.ASK_LATER
|
||||
|
||||
ins = Utils.defaultdict(set)
|
||||
outs = Utils.defaultdict(set)
|
||||
|
||||
# the .mod files to create
|
||||
for tsk in lst:
|
||||
key = tsk.uid()
|
||||
for x in bld.raw_deps[key]:
|
||||
if x.startswith('MOD@'):
|
||||
name = bld.modfile(x.replace('MOD@', ''))
|
||||
node = bld.srcnode.find_or_declare(name)
|
||||
tsk.set_outputs(node)
|
||||
outs[id(node)].add(tsk)
|
||||
|
||||
# the .mod files to use
|
||||
for tsk in lst:
|
||||
key = tsk.uid()
|
||||
for x in bld.raw_deps[key]:
|
||||
if x.startswith('USE@'):
|
||||
name = bld.modfile(x.replace('USE@', ''))
|
||||
node = bld.srcnode.find_resource(name)
|
||||
if node and node not in tsk.outputs:
|
||||
if not node in bld.node_deps[key]:
|
||||
bld.node_deps[key].append(node)
|
||||
ins[id(node)].add(tsk)
|
||||
|
||||
# if the intersection matches, set the order
|
||||
for k in ins.keys():
|
||||
for a in ins[k]:
|
||||
a.run_after.update(outs[k])
|
||||
|
||||
# the scanner cannot output nodes, so we have to set them
|
||||
# ourselves as task.dep_nodes (additional input nodes)
|
||||
tmp = []
|
||||
for t in outs[k]:
|
||||
tmp.extend(t.outputs)
|
||||
a.dep_nodes.extend(tmp)
|
||||
a.dep_nodes.sort(key=lambda x: x.abspath())
|
||||
|
||||
# the task objects have changed: clear the signature cache
|
||||
for tsk in lst:
|
||||
try:
|
||||
delattr(tsk, 'cache_sig')
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return super(fc, self).runnable_status()
|
||||
|
||||
class fcprogram(ccroot.link_task):
|
||||
"""Link fortran programs"""
|
||||
color = 'YELLOW'
|
||||
run_str = '${FC} ${LINKFLAGS} ${FCLNK_SRC_F}${SRC} ${FCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FCSTLIB_MARKER} ${FCSTLIBPATH_ST:STLIBPATH} ${FCSTLIB_ST:STLIB} ${FCSHLIB_MARKER} ${FCLIBPATH_ST:LIBPATH} ${FCLIB_ST:LIB}'
|
||||
inst_to = '${BINDIR}'
|
||||
|
||||
class fcshlib(fcprogram):
|
||||
"""Link fortran libraries"""
|
||||
inst_to = '${LIBDIR}'
|
||||
|
||||
class fcprogram_test(fcprogram):
|
||||
"""Custom link task to obtain the compiler outputs for fortran configuration tests"""
|
||||
|
||||
def can_retrieve_cache(self):
|
||||
"""This task is always executed"""
|
||||
return False
|
||||
|
||||
def runnable_status(self):
|
||||
"""This task is always executed"""
|
||||
ret = super(fcprogram_test, self).runnable_status()
|
||||
if ret == Task.SKIP_ME:
|
||||
ret = Task.RUN_ME
|
||||
return ret
|
||||
|
||||
def exec_command(self, cmd, **kw):
|
||||
"""Store the compiler std our/err onto the build context, to bld.out + bld.err"""
|
||||
bld = self.generator.bld
|
||||
|
||||
kw['shell'] = isinstance(cmd, str)
|
||||
kw['stdout'] = kw['stderr'] = Utils.subprocess.PIPE
|
||||
kw['cwd'] = bld.variant_dir
|
||||
bld.out = bld.err = ''
|
||||
|
||||
bld.to_log('command: %s\n' % cmd)
|
||||
|
||||
kw['output'] = 0
|
||||
try:
|
||||
(bld.out, bld.err) = bld.cmd_and_log(cmd, **kw)
|
||||
except Exception as e:
|
||||
return -1
|
||||
|
||||
if bld.out:
|
||||
bld.to_log("out: %s\n" % bld.out)
|
||||
if bld.err:
|
||||
bld.to_log("err: %s\n" % bld.err)
|
||||
|
||||
class fcstlib(ccroot.stlink_task):
|
||||
"""Link fortran static libraries (uses ar by default)"""
|
||||
pass # do not remove the pass statement
|
||||
|
||||
+468
@@ -0,0 +1,468 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# DC 2008
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
"""
|
||||
Fortran configuration helpers
|
||||
"""
|
||||
|
||||
import re, shutil, os, sys, string, shlex
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, after_method, before_method
|
||||
from waflib import Build, Utils
|
||||
|
||||
FC_FRAGMENT = ' program main\n end program main\n'
|
||||
FC_FRAGMENT2 = ' PROGRAM MAIN\n END\n' # what's the actual difference between these?
|
||||
|
||||
@conf
|
||||
def fc_flags(conf):
|
||||
"""
|
||||
Define common fortran configuration flags and file extensions
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['FC_SRC_F'] = []
|
||||
v['FC_TGT_F'] = ['-c', '-o']
|
||||
v['FCINCPATH_ST'] = '-I%s'
|
||||
v['FCDEFINES_ST'] = '-D%s'
|
||||
|
||||
if not v['LINK_FC']: v['LINK_FC'] = v['FC']
|
||||
v['FCLNK_SRC_F'] = []
|
||||
v['FCLNK_TGT_F'] = ['-o']
|
||||
|
||||
v['FCFLAGS_fcshlib'] = ['-fpic']
|
||||
v['LINKFLAGS_fcshlib'] = ['-shared']
|
||||
v['fcshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
v['fcstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
v['FCLIB_ST'] = '-l%s'
|
||||
v['FCLIBPATH_ST'] = '-L%s'
|
||||
v['FCSTLIB_ST'] = '-l%s'
|
||||
v['FCSTLIBPATH_ST'] = '-L%s'
|
||||
v['FCSTLIB_MARKER'] = '-Wl,-Bstatic'
|
||||
v['FCSHLIB_MARKER'] = '-Wl,-Bdynamic'
|
||||
|
||||
v['SONAME_ST'] = '-Wl,-h,%s'
|
||||
|
||||
@conf
|
||||
def fc_add_flags(conf):
|
||||
"""
|
||||
FCFLAGS?
|
||||
"""
|
||||
conf.add_os_flags('FCFLAGS')
|
||||
conf.add_os_flags('LDFLAGS', 'LINKFLAGS')
|
||||
|
||||
@conf
|
||||
def check_fortran(self, *k, **kw):
|
||||
"""See if the fortran compiler works by compiling a simple fortran program"""
|
||||
self.check_cc(
|
||||
fragment = FC_FRAGMENT,
|
||||
compile_filename = 'test.f',
|
||||
features = 'fc fcprogram',
|
||||
msg = 'Compiling a simple fortran app')
|
||||
|
||||
@conf
|
||||
def check_fc(self, *k, **kw):
|
||||
"""
|
||||
Same as :py:func:`waflib.Tools.c_config.check` but default to the *Fortran* programming language
|
||||
(Overriding the C defaults in :py:func:`waflib.Tools.c_config.validate_c` here)
|
||||
"""
|
||||
kw['compiler'] = 'fc'
|
||||
if not 'compile_mode' in kw:
|
||||
kw['compile_mode'] = 'fc'
|
||||
if not 'type' in kw:
|
||||
kw['type'] = 'fcprogram'
|
||||
if not 'compile_filename' in kw:
|
||||
kw['compile_filename'] = 'test.f90'
|
||||
if not 'code' in kw:
|
||||
kw['code'] = FC_FRAGMENT
|
||||
return self.check(*k, **kw)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# --- These are the default platform modifiers, refactored here for
|
||||
# convenience. gfortran and g95 have much overlap.
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@conf
|
||||
def fortran_modifier_darwin(conf):
|
||||
"""
|
||||
Define fortran flags and extensions for the OSX systems
|
||||
"""
|
||||
v = conf.env
|
||||
v['FCFLAGS_fcshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_fcshlib'] = ['-dynamiclib', '-Wl,-compatibility_version,1', '-Wl,-current_version,1']
|
||||
v['fcshlib_PATTERN'] = 'lib%s.dylib'
|
||||
v['FRAMEWORKPATH_ST'] = '-F%s'
|
||||
v['FRAMEWORK_ST'] = '-framework %s'
|
||||
|
||||
v['LINKFLAGS_fcstlib'] = []
|
||||
|
||||
v['FCSHLIB_MARKER'] = ''
|
||||
v['FCSTLIB_MARKER'] = ''
|
||||
v['SONAME_ST'] = ''
|
||||
|
||||
|
||||
@conf
|
||||
def fortran_modifier_win32(conf):
|
||||
"""Define fortran flags for the windows platforms"""
|
||||
v = conf.env
|
||||
v['fcprogram_PATTERN'] = v['fcprogram_test_PATTERN'] = '%s.exe'
|
||||
|
||||
v['fcshlib_PATTERN'] = '%s.dll'
|
||||
v['implib_PATTERN'] = 'lib%s.dll.a'
|
||||
v['IMPLIB_ST'] = '-Wl,--out-implib,%s'
|
||||
|
||||
v['FCFLAGS_fcshlib'] = []
|
||||
|
||||
v.append_value('FCFLAGS_fcshlib', ['-DDLL_EXPORT']) # TODO adding nonstandard defines like this DLL_EXPORT is not a good idea
|
||||
|
||||
# Auto-import is enabled by default even without this option,
|
||||
# but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages
|
||||
# that the linker emits otherwise.
|
||||
v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])
|
||||
|
||||
@conf
|
||||
def fortran_modifier_cygwin(conf):
|
||||
"""Define fortran flags for use on cygwin"""
|
||||
fortran_modifier_win32(conf)
|
||||
v = conf.env
|
||||
v['fcshlib_PATTERN'] = 'cyg%s.dll'
|
||||
v.append_value('LINKFLAGS_fcshlib', ['-Wl,--enable-auto-image-base'])
|
||||
v['FCFLAGS_fcshlib'] = []
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@conf
|
||||
def check_fortran_dummy_main(self, *k, **kw):
|
||||
"""
|
||||
Guess if a main function is needed by compiling a code snippet with
|
||||
the C compiler and link with the Fortran compiler
|
||||
|
||||
TODO: (DC)
|
||||
- handling dialects (F77, F90, etc... -> needs core support first)
|
||||
- fix dummy main check (AC_FC_DUMMY_MAIN vs AC_FC_MAIN)
|
||||
|
||||
TODO: what does the above mean? (ita)
|
||||
"""
|
||||
|
||||
if not self.env.CC:
|
||||
self.fatal('A c compiler is required for check_fortran_dummy_main')
|
||||
|
||||
lst = ['MAIN__', '__MAIN', '_MAIN', 'MAIN_', 'MAIN']
|
||||
lst.extend([m.lower() for m in lst])
|
||||
lst.append('')
|
||||
|
||||
self.start_msg('Detecting whether we need a dummy main')
|
||||
for main in lst:
|
||||
kw['fortran_main'] = main
|
||||
try:
|
||||
self.check_cc(
|
||||
fragment = 'int %s() { return 0; }\n' % (main or 'test'),
|
||||
features = 'c fcprogram',
|
||||
mandatory = True
|
||||
)
|
||||
if not main:
|
||||
self.env.FC_MAIN = -1
|
||||
self.end_msg('no')
|
||||
else:
|
||||
self.env.FC_MAIN = main
|
||||
self.end_msg('yes %s' % main)
|
||||
break
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
self.end_msg('not found')
|
||||
self.fatal('could not detect whether fortran requires a dummy main, see the config.log')
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
GCC_DRIVER_LINE = re.compile('^Driving:')
|
||||
POSIX_STATIC_EXT = re.compile('\S+\.a')
|
||||
POSIX_LIB_FLAGS = re.compile('-l\S+')
|
||||
|
||||
@conf
|
||||
def is_link_verbose(self, txt):
|
||||
"""Return True if 'useful' link options can be found in txt"""
|
||||
assert isinstance(txt, str)
|
||||
for line in txt.splitlines():
|
||||
if not GCC_DRIVER_LINE.search(line):
|
||||
if POSIX_STATIC_EXT.search(line) or POSIX_LIB_FLAGS.search(line):
|
||||
return True
|
||||
return False
|
||||
|
||||
@conf
|
||||
def check_fortran_verbose_flag(self, *k, **kw):
|
||||
"""
|
||||
Check what kind of verbose (-v) flag works, then set it to env.FC_VERBOSE_FLAG
|
||||
"""
|
||||
self.start_msg('fortran link verbose flag')
|
||||
for x in ['-v', '--verbose', '-verbose', '-V']:
|
||||
try:
|
||||
self.check_cc(
|
||||
features = 'fc fcprogram_test',
|
||||
fragment = FC_FRAGMENT2,
|
||||
compile_filename = 'test.f',
|
||||
linkflags = [x],
|
||||
mandatory=True
|
||||
)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
# output is on stderr or stdout (for xlf)
|
||||
if self.is_link_verbose(self.test_bld.err) or self.is_link_verbose(self.test_bld.out):
|
||||
self.end_msg(x)
|
||||
break
|
||||
else:
|
||||
self.end_msg('failure')
|
||||
self.fatal('Could not obtain the fortran link verbose flag (see config.log)')
|
||||
|
||||
self.env.FC_VERBOSE_FLAG = x
|
||||
return x
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# linkflags which match those are ignored
|
||||
LINKFLAGS_IGNORED = [r'-lang*', r'-lcrt[a-zA-Z0-9\.]*\.o', r'-lc$', r'-lSystem', r'-libmil', r'-LIST:*', r'-LNO:*']
|
||||
if os.name == 'nt':
|
||||
LINKFLAGS_IGNORED.extend([r'-lfrt*', r'-luser32', r'-lkernel32', r'-ladvapi32', r'-lmsvcrt', r'-lshell32', r'-lmingw', r'-lmoldname'])
|
||||
else:
|
||||
LINKFLAGS_IGNORED.append(r'-lgcc*')
|
||||
RLINKFLAGS_IGNORED = [re.compile(f) for f in LINKFLAGS_IGNORED]
|
||||
|
||||
def _match_ignore(line):
|
||||
"""Returns True if the line should be ignored (fortran test for verbosity)."""
|
||||
for i in RLINKFLAGS_IGNORED:
|
||||
if i.match(line):
|
||||
return True
|
||||
return False
|
||||
|
||||
def parse_fortran_link(lines):
|
||||
"""Given the output of verbose link of Fortran compiler, this returns a
|
||||
list of flags necessary for linking using the standard linker."""
|
||||
# TODO: On windows ?
|
||||
final_flags = []
|
||||
for line in lines:
|
||||
if not GCC_DRIVER_LINE.match(line):
|
||||
_parse_flink_line(line, final_flags)
|
||||
return final_flags
|
||||
|
||||
SPACE_OPTS = re.compile('^-[LRuYz]$')
|
||||
NOSPACE_OPTS = re.compile('^-[RL]')
|
||||
|
||||
def _parse_flink_line(line, final_flags):
|
||||
"""private"""
|
||||
lexer = shlex.shlex(line, posix = True)
|
||||
lexer.whitespace_split = True
|
||||
|
||||
t = lexer.get_token()
|
||||
tmp_flags = []
|
||||
while t:
|
||||
def parse(token):
|
||||
# Here we go (convention for wildcard is shell, not regex !)
|
||||
# 1 TODO: we first get some root .a libraries
|
||||
# 2 TODO: take everything starting by -bI:*
|
||||
# 3 Ignore the following flags: -lang* | -lcrt*.o | -lc |
|
||||
# -lgcc* | -lSystem | -libmil | -LANG:=* | -LIST:* | -LNO:*)
|
||||
# 4 take into account -lkernel32
|
||||
# 5 For options of the kind -[[LRuYz]], as they take one argument
|
||||
# after, the actual option is the next token
|
||||
# 6 For -YP,*: take and replace by -Larg where arg is the old
|
||||
# argument
|
||||
# 7 For -[lLR]*: take
|
||||
|
||||
# step 3
|
||||
if _match_ignore(token):
|
||||
pass
|
||||
# step 4
|
||||
elif token.startswith('-lkernel32') and sys.platform == 'cygwin':
|
||||
tmp_flags.append(token)
|
||||
# step 5
|
||||
elif SPACE_OPTS.match(token):
|
||||
t = lexer.get_token()
|
||||
if t.startswith('P,'):
|
||||
t = t[2:]
|
||||
for opt in t.split(os.pathsep):
|
||||
tmp_flags.append('-L%s' % opt)
|
||||
# step 6
|
||||
elif NOSPACE_OPTS.match(token):
|
||||
tmp_flags.append(token)
|
||||
# step 7
|
||||
elif POSIX_LIB_FLAGS.match(token):
|
||||
tmp_flags.append(token)
|
||||
else:
|
||||
# ignore anything not explicitely taken into account
|
||||
pass
|
||||
|
||||
t = lexer.get_token()
|
||||
return t
|
||||
t = parse(t)
|
||||
|
||||
final_flags.extend(tmp_flags)
|
||||
return final_flags
|
||||
|
||||
@conf
|
||||
def check_fortran_clib(self, autoadd=True, *k, **kw):
|
||||
"""
|
||||
Obtain the flags for linking with the C library
|
||||
if this check works, add uselib='CLIB' to your task generators
|
||||
"""
|
||||
if not self.env.FC_VERBOSE_FLAG:
|
||||
self.fatal('env.FC_VERBOSE_FLAG is not set: execute check_fortran_verbose_flag?')
|
||||
|
||||
self.start_msg('Getting fortran runtime link flags')
|
||||
try:
|
||||
self.check_cc(
|
||||
fragment = FC_FRAGMENT2,
|
||||
compile_filename = 'test.f',
|
||||
features = 'fc fcprogram_test',
|
||||
linkflags = [self.env.FC_VERBOSE_FLAG]
|
||||
)
|
||||
except Exception:
|
||||
self.end_msg(False)
|
||||
if kw.get('mandatory', True):
|
||||
conf.fatal('Could not find the c library flags')
|
||||
else:
|
||||
out = self.test_bld.err
|
||||
flags = parse_fortran_link(out.splitlines())
|
||||
self.end_msg('ok (%s)' % ' '.join(flags))
|
||||
self.env.LINKFLAGS_CLIB = flags
|
||||
return flags
|
||||
return []
|
||||
|
||||
def getoutput(conf, cmd, stdin=False):
|
||||
"""
|
||||
TODO a bit redundant, can be removed anytime
|
||||
"""
|
||||
if stdin:
|
||||
stdin = Utils.subprocess.PIPE
|
||||
else:
|
||||
stdin = None
|
||||
env = conf.env.env or None
|
||||
try:
|
||||
p = Utils.subprocess.Popen(cmd, stdin=stdin, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=env)
|
||||
if stdin:
|
||||
p.stdin.write('\n'.encode())
|
||||
out, err = p.communicate()
|
||||
except Exception:
|
||||
conf.fatal('could not determine the compiler version %r' % cmd)
|
||||
if not isinstance(out, str):
|
||||
out = out.decode(sys.stdout.encoding or 'iso8859-1')
|
||||
if not isinstance(err, str):
|
||||
err = err.decode(sys.stdout.encoding or 'iso8859-1')
|
||||
return (out, err)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
ROUTINES_CODE = """\
|
||||
subroutine foobar()
|
||||
return
|
||||
end
|
||||
subroutine foo_bar()
|
||||
return
|
||||
end
|
||||
"""
|
||||
|
||||
MAIN_CODE = """
|
||||
void %(dummy_func_nounder)s(void);
|
||||
void %(dummy_func_under)s(void);
|
||||
int %(main_func_name)s() {
|
||||
%(dummy_func_nounder)s();
|
||||
%(dummy_func_under)s();
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
@feature('link_main_routines_func')
|
||||
@before_method('process_source')
|
||||
def link_main_routines_tg_method(self):
|
||||
"""
|
||||
The configuration test declares a unique task generator,
|
||||
so we create other task generators from there for fortran link tests
|
||||
"""
|
||||
def write_test_file(task):
|
||||
task.outputs[0].write(task.generator.code)
|
||||
bld = self.bld
|
||||
bld(rule=write_test_file, target='main.c', code=MAIN_CODE % self.__dict__)
|
||||
bld(rule=write_test_file, target='test.f', code=ROUTINES_CODE)
|
||||
bld(features='fc fcstlib', source='test.f', target='test')
|
||||
bld(features='c fcprogram', source='main.c', target='app', use='test')
|
||||
|
||||
def mangling_schemes():
|
||||
"""
|
||||
Generate triplets for use with mangle_name
|
||||
(used in check_fortran_mangling)
|
||||
the order is tuned for gfortan
|
||||
"""
|
||||
for u in ['_', '']:
|
||||
for du in ['', '_']:
|
||||
for c in ["lower", "upper"]:
|
||||
yield (u, du, c)
|
||||
|
||||
def mangle_name(u, du, c, name):
|
||||
"""Mangle a name from a triplet (used in check_fortran_mangling)"""
|
||||
return getattr(name, c)() + u + (name.find('_') != -1 and du or '')
|
||||
|
||||
@conf
|
||||
def check_fortran_mangling(self, *k, **kw):
|
||||
"""
|
||||
Detect the mangling scheme, sets FORTRAN_MANGLING to the triplet found
|
||||
|
||||
This test will compile a fortran static library, then link a c app against it
|
||||
"""
|
||||
if not self.env.CC:
|
||||
self.fatal('A c compiler is required for link_main_routines')
|
||||
if not self.env.FC:
|
||||
self.fatal('A fortran compiler is required for link_main_routines')
|
||||
if not self.env.FC_MAIN:
|
||||
self.fatal('Checking for mangling requires self.env.FC_MAIN (execute "check_fortran_dummy_main" first?)')
|
||||
|
||||
self.start_msg('Getting fortran mangling scheme')
|
||||
for (u, du, c) in mangling_schemes():
|
||||
try:
|
||||
self.check_cc(
|
||||
compile_filename = [],
|
||||
features = 'link_main_routines_func',
|
||||
msg = 'nomsg',
|
||||
errmsg = 'nomsg',
|
||||
mandatory=True,
|
||||
dummy_func_nounder = mangle_name(u, du, c, "foobar"),
|
||||
dummy_func_under = mangle_name(u, du, c, "foo_bar"),
|
||||
main_func_name = self.env.FC_MAIN
|
||||
)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
self.end_msg("ok ('%s', '%s', '%s-case')" % (u, du, c))
|
||||
self.env.FORTRAN_MANGLING = (u, du, c)
|
||||
break
|
||||
else:
|
||||
self.end_msg(False)
|
||||
self.fatal('mangler not found')
|
||||
|
||||
return (u, du, c)
|
||||
|
||||
@feature('pyext')
|
||||
@before_method('propagate_uselib_vars', 'apply_link')
|
||||
def set_lib_pat(self):
|
||||
"""Set the fortran flags for linking with the python library"""
|
||||
self.env['fcshlib_PATTERN'] = self.env['pyext_PATTERN']
|
||||
|
||||
@conf
|
||||
def detect_openmp(self):
|
||||
for x in ['-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp']:
|
||||
try:
|
||||
self.check_fc(
|
||||
msg='Checking for OpenMP flag %s' % x,
|
||||
fragment='program main\n call omp_get_num_threads()\nend program main',
|
||||
fcflags=x,
|
||||
linkflags=x,
|
||||
uselib_store='OPENMP'
|
||||
)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
else:
|
||||
self.fatal('Could not find OpenMP')
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# DC 2008
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
import re
|
||||
|
||||
from waflib import Utils, Task, TaskGen, Logs
|
||||
from waflib.TaskGen import feature, before_method, after_method, extension
|
||||
from waflib.Configure import conf
|
||||
|
||||
INC_REGEX = """(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
|
||||
USE_REGEX = """(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""
|
||||
MOD_REGEX = """(?:^|;)\s*MODULE(?!\s*PROCEDURE)(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""
|
||||
|
||||
re_inc = re.compile(INC_REGEX, re.I)
|
||||
re_use = re.compile(USE_REGEX, re.I)
|
||||
re_mod = re.compile(MOD_REGEX, re.I)
|
||||
|
||||
class fortran_parser(object):
|
||||
"""
|
||||
This parser will return:
|
||||
|
||||
* the nodes corresponding to the module names that will be produced
|
||||
* the nodes corresponding to the include files used
|
||||
* the module names used by the fortran file
|
||||
"""
|
||||
|
||||
def __init__(self, incpaths):
|
||||
self.seen = []
|
||||
"""Files already parsed"""
|
||||
|
||||
self.nodes = []
|
||||
"""List of :py:class:`waflib.Node.Node` representing the dependencies to return"""
|
||||
|
||||
self.names = []
|
||||
"""List of module names to return"""
|
||||
|
||||
self.incpaths = incpaths
|
||||
"""List of :py:class:`waflib.Node.Node` representing the include paths"""
|
||||
|
||||
def find_deps(self, node):
|
||||
"""
|
||||
Parse a fortran file to read the dependencies used and provided
|
||||
|
||||
:param node: fortran file to read
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
:return: lists representing the includes, the modules used, and the modules created by a fortran file
|
||||
:rtype: tuple of list of strings
|
||||
"""
|
||||
txt = node.read()
|
||||
incs = []
|
||||
uses = []
|
||||
mods = []
|
||||
for line in txt.splitlines():
|
||||
# line by line regexp search? optimize?
|
||||
m = re_inc.search(line)
|
||||
if m:
|
||||
incs.append(m.group(1))
|
||||
m = re_use.search(line)
|
||||
if m:
|
||||
uses.append(m.group(1))
|
||||
m = re_mod.search(line)
|
||||
if m:
|
||||
mods.append(m.group(1))
|
||||
return (incs, uses, mods)
|
||||
|
||||
def start(self, node):
|
||||
"""
|
||||
Start the parsing. Use the stack self.waiting to hold the nodes to iterate on
|
||||
|
||||
:param node: fortran file
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
self.waiting = [node]
|
||||
while self.waiting:
|
||||
nd = self.waiting.pop(0)
|
||||
self.iter(nd)
|
||||
|
||||
def iter(self, node):
|
||||
"""
|
||||
Process a single file in the search for dependencies, extract the files used
|
||||
the modules used, and the modules provided.
|
||||
"""
|
||||
path = node.abspath()
|
||||
incs, uses, mods = self.find_deps(node)
|
||||
for x in incs:
|
||||
if x in self.seen:
|
||||
continue
|
||||
self.seen.append(x)
|
||||
self.tryfind_header(x)
|
||||
|
||||
for x in uses:
|
||||
name = "USE@%s" % x
|
||||
if not name in self.names:
|
||||
self.names.append(name)
|
||||
|
||||
for x in mods:
|
||||
name = "MOD@%s" % x
|
||||
if not name in self.names:
|
||||
self.names.append(name)
|
||||
|
||||
def tryfind_header(self, filename):
|
||||
"""
|
||||
Try to find an include and add it the nodes to process
|
||||
|
||||
:param filename: file name
|
||||
:type filename: string
|
||||
"""
|
||||
found = None
|
||||
for n in self.incpaths:
|
||||
found = n.find_resource(filename)
|
||||
if found:
|
||||
self.nodes.append(found)
|
||||
self.waiting.append(found)
|
||||
break
|
||||
if not found:
|
||||
if not filename in self.names:
|
||||
self.names.append(filename)
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# John O'Meara, 2006
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
The **flex** program is a code generator which creates C or C++ files.
|
||||
The generated files are compiled into object files.
|
||||
"""
|
||||
|
||||
import waflib.TaskGen, os, re
|
||||
|
||||
def decide_ext(self, node):
|
||||
if 'cxx' in self.features:
|
||||
return ['.lex.cc']
|
||||
return ['.lex.c']
|
||||
|
||||
def flexfun(tsk):
|
||||
env = tsk.env
|
||||
bld = tsk.generator.bld
|
||||
wd = bld.variant_dir
|
||||
def to_list(xx):
|
||||
if isinstance(xx, str): return [xx]
|
||||
return xx
|
||||
tsk.last_cmd = lst = []
|
||||
lst.extend(to_list(env['FLEX']))
|
||||
lst.extend(to_list(env['FLEXFLAGS']))
|
||||
inputs = [a.path_from(bld.bldnode) for a in tsk.inputs]
|
||||
if env.FLEX_MSYS:
|
||||
inputs = [x.replace(os.sep, '/') for x in inputs]
|
||||
lst.extend(inputs)
|
||||
lst = [x for x in lst if x]
|
||||
txt = bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0)
|
||||
tsk.outputs[0].write(txt.replace('\r\n', '\n').replace('\r', '\n')) # issue #1207
|
||||
|
||||
waflib.TaskGen.declare_chain(
|
||||
name = 'flex',
|
||||
rule = flexfun, # issue #854
|
||||
ext_in = '.l',
|
||||
decider = decide_ext,
|
||||
)
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the *flex* program
|
||||
"""
|
||||
conf.find_program('flex', var='FLEX')
|
||||
conf.env.FLEXFLAGS = ['-t']
|
||||
|
||||
if re.search (r"\\msys\\[0-9.]+\\bin\\flex.exe$", conf.env.FLEX):
|
||||
# this is the flex shipped with MSYS
|
||||
conf.env.FLEX_MSYS = True
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# KWS 2010
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
import re
|
||||
from waflib import Utils
|
||||
from waflib.Tools import fc, fc_config, fc_scan, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_g95(conf):
|
||||
fc = conf.find_program('g95', var='FC')
|
||||
fc = conf.cmd_to_list(fc)
|
||||
conf.get_g95_version(fc)
|
||||
conf.env.FC_NAME = 'G95'
|
||||
|
||||
@conf
|
||||
def g95_flags(conf):
|
||||
v = conf.env
|
||||
v['FCFLAGS_fcshlib'] = ['-fPIC']
|
||||
v['FORTRANMODFLAG'] = ['-fmod=', ''] # template for module path
|
||||
v['FCFLAGS_DEBUG'] = ['-Werror'] # why not
|
||||
|
||||
@conf
|
||||
def g95_modifier_win32(conf):
|
||||
fc_config.fortran_modifier_win32(conf)
|
||||
|
||||
@conf
|
||||
def g95_modifier_cygwin(conf):
|
||||
fc_config.fortran_modifier_cygwin(conf)
|
||||
|
||||
@conf
|
||||
def g95_modifier_darwin(conf):
|
||||
fc_config.fortran_modifier_darwin(conf)
|
||||
|
||||
@conf
|
||||
def g95_modifier_platform(conf):
|
||||
dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
|
||||
g95_modifier_func = getattr(conf, 'g95_modifier_' + dest_os, None)
|
||||
if g95_modifier_func:
|
||||
g95_modifier_func()
|
||||
|
||||
@conf
|
||||
def get_g95_version(conf, fc):
|
||||
"""get the compiler version"""
|
||||
|
||||
version_re = re.compile(r"g95\s*(?P<major>\d*)\.(?P<minor>\d*)").search
|
||||
cmd = fc + ['--version']
|
||||
out, err = fc_config.getoutput(conf, cmd, stdin=False)
|
||||
if out:
|
||||
match = version_re(out)
|
||||
else:
|
||||
match = version_re(err)
|
||||
if not match:
|
||||
conf.fatal('cannot determine g95 version')
|
||||
k = match.groupdict()
|
||||
conf.env['FC_VERSION'] = (k['major'], k['minor'])
|
||||
|
||||
def configure(conf):
|
||||
conf.find_g95()
|
||||
conf.find_ar()
|
||||
conf.fc_flags()
|
||||
conf.fc_add_flags()
|
||||
conf.g95_flags()
|
||||
conf.g95_modifier_platform()
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2008-2010 (ita)
|
||||
|
||||
"Detect as/gas/gcc for compiling assembly files"
|
||||
|
||||
import waflib.Tools.asm # - leave this
|
||||
from waflib.Tools import ar
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Find the programs gas/as/gcc and set the variable *AS*
|
||||
"""
|
||||
conf.find_program(['gas', 'gcc'], var='AS')
|
||||
conf.env.AS_TGT_F = ['-c', '-o']
|
||||
conf.env.ASLNK_TGT_F = ['-o']
|
||||
conf.find_ar()
|
||||
conf.load('asm')
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
# Yinon Ehrlich, 2009
|
||||
|
||||
"""
|
||||
gcc/llvm detection.
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib import Configure, Options, Utils
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_gcc(conf):
|
||||
"""
|
||||
Find the program gcc, and if present, try to detect its version number
|
||||
"""
|
||||
cc = conf.find_program(['gcc', 'cc'], var='CC')
|
||||
cc = conf.cmd_to_list(cc)
|
||||
conf.get_cc_version(cc, gcc=True)
|
||||
conf.env.CC_NAME = 'gcc'
|
||||
conf.env.CC = cc
|
||||
|
||||
@conf
|
||||
def gcc_common_flags(conf):
|
||||
"""
|
||||
Common flags for gcc on nearly all platforms
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['CC_SRC_F'] = []
|
||||
v['CC_TGT_F'] = ['-c', '-o']
|
||||
|
||||
# linker
|
||||
if not v['LINK_CC']: v['LINK_CC'] = v['CC']
|
||||
v['CCLNK_SRC_F'] = []
|
||||
v['CCLNK_TGT_F'] = ['-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
v['RPATH_ST'] = '-Wl,-rpath,%s'
|
||||
|
||||
v['SONAME_ST'] = '-Wl,-h,%s'
|
||||
v['SHLIB_MARKER'] = '-Wl,-Bdynamic'
|
||||
v['STLIB_MARKER'] = '-Wl,-Bstatic'
|
||||
|
||||
# program
|
||||
v['cprogram_PATTERN'] = '%s'
|
||||
|
||||
# shared librar
|
||||
v['CFLAGS_cshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_cshlib'] = ['-shared']
|
||||
v['cshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
# static lib
|
||||
v['LINKFLAGS_cstlib'] = ['-Wl,-Bstatic']
|
||||
v['cstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
# osx stuff
|
||||
v['LINKFLAGS_MACBUNDLE'] = ['-bundle', '-undefined', 'dynamic_lookup']
|
||||
v['CFLAGS_MACBUNDLE'] = ['-fPIC']
|
||||
v['macbundle_PATTERN'] = '%s.bundle'
|
||||
|
||||
@conf
|
||||
def gcc_modifier_win32(conf):
|
||||
"""Configuration flags for executing gcc on Windows"""
|
||||
v = conf.env
|
||||
v['cprogram_PATTERN'] = '%s.exe'
|
||||
|
||||
v['cshlib_PATTERN'] = '%s.dll'
|
||||
v['implib_PATTERN'] = 'lib%s.dll.a'
|
||||
v['IMPLIB_ST'] = '-Wl,--out-implib,%s'
|
||||
|
||||
v['CFLAGS_cshlib'] = []
|
||||
|
||||
# Auto-import is enabled by default even without this option,
|
||||
# but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages
|
||||
# that the linker emits otherwise.
|
||||
v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])
|
||||
|
||||
@conf
|
||||
def gcc_modifier_cygwin(conf):
|
||||
"""Configuration flags for executing gcc on Cygwin"""
|
||||
gcc_modifier_win32(conf)
|
||||
v = conf.env
|
||||
v['cshlib_PATTERN'] = 'cyg%s.dll'
|
||||
v.append_value('LINKFLAGS_cshlib', ['-Wl,--enable-auto-image-base'])
|
||||
v['CFLAGS_cshlib'] = []
|
||||
|
||||
@conf
|
||||
def gcc_modifier_darwin(conf):
|
||||
"""Configuration flags for executing gcc on MacOS"""
|
||||
v = conf.env
|
||||
v['CFLAGS_cshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_cshlib'] = ['-dynamiclib', '-Wl,-compatibility_version,1', '-Wl,-current_version,1']
|
||||
v['cshlib_PATTERN'] = 'lib%s.dylib'
|
||||
v['FRAMEWORKPATH_ST'] = '-F%s'
|
||||
v['FRAMEWORK_ST'] = ['-framework']
|
||||
v['ARCH_ST'] = ['-arch']
|
||||
|
||||
v['LINKFLAGS_cstlib'] = []
|
||||
|
||||
v['SHLIB_MARKER'] = []
|
||||
v['STLIB_MARKER'] = []
|
||||
v['SONAME_ST'] = []
|
||||
|
||||
@conf
|
||||
def gcc_modifier_aix(conf):
|
||||
"""Configuration flags for executing gcc on AIX"""
|
||||
v = conf.env
|
||||
v['LINKFLAGS_cprogram'] = ['-Wl,-brtl']
|
||||
v['LINKFLAGS_cshlib'] = ['-shared','-Wl,-brtl,-bexpfull']
|
||||
v['SHLIB_MARKER'] = []
|
||||
|
||||
@conf
|
||||
def gcc_modifier_hpux(conf):
|
||||
v = conf.env
|
||||
v['SHLIB_MARKER'] = []
|
||||
v['STLIB_MARKER'] = '-Bstatic'
|
||||
v['CFLAGS_cshlib'] = ['-fPIC','-DPIC']
|
||||
v['cshlib_PATTERN'] = 'lib%s.sl'
|
||||
|
||||
@conf
|
||||
def gcc_modifier_platform(conf):
|
||||
"""Execute platform-specific functions based on *gcc_modifier_+NAME*"""
|
||||
# * set configurations specific for a platform.
|
||||
# * the destination platform is detected automatically by looking at the macros the compiler predefines,
|
||||
# and if it's not recognised, it fallbacks to sys.platform.
|
||||
gcc_modifier_func = getattr(conf, 'gcc_modifier_' + conf.env.DEST_OS, None)
|
||||
if gcc_modifier_func:
|
||||
gcc_modifier_func()
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Configuration for gcc
|
||||
"""
|
||||
conf.find_gcc()
|
||||
conf.find_ar()
|
||||
conf.gcc_common_flags()
|
||||
conf.gcc_modifier_platform()
|
||||
conf.cc_load_tools()
|
||||
conf.cc_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Carlos Rafael Giani, 2007 (dv)
|
||||
|
||||
import sys
|
||||
from waflib.Tools import ar, d
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_gdc(conf):
|
||||
"""
|
||||
Find the program gdc and set the variable *D*
|
||||
"""
|
||||
conf.find_program('gdc', var='D')
|
||||
|
||||
out = conf.cmd_and_log([conf.env.D, '--version'])
|
||||
if out.find("gdc ") == -1:
|
||||
conf.fatal("detected compiler is not gdc")
|
||||
|
||||
@conf
|
||||
def common_flags_gdc(conf):
|
||||
"""
|
||||
Set the flags required by *gdc*
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
# _DFLAGS _DIMPORTFLAGS
|
||||
|
||||
# for mory info about the meaning of this dict see dmd.py
|
||||
v['DFLAGS'] = []
|
||||
|
||||
v['D_SRC_F'] = ['-c']
|
||||
v['D_TGT_F'] = '-o%s'
|
||||
|
||||
# linker
|
||||
v['D_LINKER'] = v['D']
|
||||
v['DLNK_SRC_F'] = ''
|
||||
v['DLNK_TGT_F'] = '-o%s'
|
||||
v['DINC_ST'] = '-I%s'
|
||||
|
||||
v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''
|
||||
v['DSTLIB_ST'] = v['DSHLIB_ST'] = '-l%s'
|
||||
v['DSTLIBPATH_ST'] = v['DLIBPATH_ST'] = '-L%s'
|
||||
|
||||
v['LINKFLAGS_dshlib'] = ['-shared']
|
||||
|
||||
v['DHEADER_ext'] = '.di'
|
||||
v.DFLAGS_d_with_header = '-fintfc'
|
||||
v['D_HDR_F'] = '-fintfc-file=%s'
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Configuration for gdc
|
||||
"""
|
||||
conf.find_gdc()
|
||||
conf.load('ar')
|
||||
conf.load('d')
|
||||
conf.common_flags_gdc()
|
||||
conf.d_platform_flags()
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# DC 2008
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
import re
|
||||
from waflib import Utils
|
||||
from waflib.Tools import fc, fc_config, fc_scan, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_gfortran(conf):
|
||||
"""Find the gfortran program (will look in the environment variable 'FC')"""
|
||||
fc = conf.find_program(['gfortran','g77'], var='FC')
|
||||
# (fallback to g77 for systems, where no gfortran is available)
|
||||
fc = conf.cmd_to_list(fc)
|
||||
conf.get_gfortran_version(fc)
|
||||
conf.env.FC_NAME = 'GFORTRAN'
|
||||
|
||||
@conf
|
||||
def gfortran_flags(conf):
|
||||
v = conf.env
|
||||
v['FCFLAGS_fcshlib'] = ['-fPIC']
|
||||
v['FORTRANMODFLAG'] = ['-J', ''] # template for module path
|
||||
v['FCFLAGS_DEBUG'] = ['-Werror'] # why not
|
||||
|
||||
@conf
|
||||
def gfortran_modifier_win32(conf):
|
||||
fc_config.fortran_modifier_win32(conf)
|
||||
|
||||
@conf
|
||||
def gfortran_modifier_cygwin(conf):
|
||||
fc_config.fortran_modifier_cygwin(conf)
|
||||
|
||||
@conf
|
||||
def gfortran_modifier_darwin(conf):
|
||||
fc_config.fortran_modifier_darwin(conf)
|
||||
|
||||
@conf
|
||||
def gfortran_modifier_platform(conf):
|
||||
dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
|
||||
gfortran_modifier_func = getattr(conf, 'gfortran_modifier_' + dest_os, None)
|
||||
if gfortran_modifier_func:
|
||||
gfortran_modifier_func()
|
||||
|
||||
@conf
|
||||
def get_gfortran_version(conf, fc):
|
||||
"""Get the compiler version"""
|
||||
|
||||
# ensure this is actually gfortran, not an imposter.
|
||||
version_re = re.compile(r"GNU\s*Fortran", re.I).search
|
||||
cmd = fc + ['--version']
|
||||
out, err = fc_config.getoutput(conf, cmd, stdin=False)
|
||||
if out: match = version_re(out)
|
||||
else: match = version_re(err)
|
||||
if not match:
|
||||
conf.fatal('Could not determine the compiler type')
|
||||
|
||||
# --- now get more detailed info -- see c_config.get_cc_version
|
||||
cmd = fc + ['-dM', '-E', '-']
|
||||
out, err = fc_config.getoutput(conf, cmd, stdin=True)
|
||||
|
||||
if out.find('__GNUC__') < 0:
|
||||
conf.fatal('Could not determine the compiler type')
|
||||
|
||||
k = {}
|
||||
out = out.split('\n')
|
||||
import shlex
|
||||
|
||||
for line in out:
|
||||
lst = shlex.split(line)
|
||||
if len(lst)>2:
|
||||
key = lst[1]
|
||||
val = lst[2]
|
||||
k[key] = val
|
||||
|
||||
def isD(var):
|
||||
return var in k
|
||||
|
||||
def isT(var):
|
||||
return var in k and k[var] != '0'
|
||||
|
||||
conf.env['FC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
|
||||
|
||||
def configure(conf):
|
||||
conf.find_gfortran()
|
||||
conf.find_ar()
|
||||
conf.fc_flags()
|
||||
conf.fc_add_flags()
|
||||
conf.gfortran_flags()
|
||||
conf.gfortran_modifier_platform()
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
Support for GLib2 tools:
|
||||
|
||||
* marshal
|
||||
* enums
|
||||
* gsettings
|
||||
"""
|
||||
|
||||
import os
|
||||
from waflib import Task, Utils, Options, Errors, Logs
|
||||
from waflib.TaskGen import taskgen_method, before_method, after_method, feature
|
||||
|
||||
################## marshal files
|
||||
|
||||
@taskgen_method
|
||||
def add_marshal_file(self, filename, prefix):
|
||||
"""
|
||||
Add a file to the list of marshal files to process. Store them in the attribute *marshal_list*.
|
||||
|
||||
:param filename: xml file to compile
|
||||
:type filename: string
|
||||
:param prefix: marshal prefix (--prefix=prefix)
|
||||
:type prefix: string
|
||||
"""
|
||||
if not hasattr(self, 'marshal_list'):
|
||||
self.marshal_list = []
|
||||
self.meths.append('process_marshal')
|
||||
self.marshal_list.append((filename, prefix))
|
||||
|
||||
@before_method('process_source')
|
||||
def process_marshal(self):
|
||||
"""
|
||||
Process the marshal files stored in the attribute *marshal_list* to create :py:class:`waflib.Tools.glib2.glib_genmarshal` instances.
|
||||
Add the c file created to the list of source to process.
|
||||
"""
|
||||
for f, prefix in getattr(self, 'marshal_list', []):
|
||||
node = self.path.find_resource(f)
|
||||
|
||||
if not node:
|
||||
raise Errors.WafError('file not found %r' % f)
|
||||
|
||||
h_node = node.change_ext('.h')
|
||||
c_node = node.change_ext('.c')
|
||||
|
||||
task = self.create_task('glib_genmarshal', node, [h_node, c_node])
|
||||
task.env.GLIB_GENMARSHAL_PREFIX = prefix
|
||||
self.source = self.to_nodes(getattr(self, 'source', []))
|
||||
self.source.append(c_node)
|
||||
|
||||
class glib_genmarshal(Task.Task):
|
||||
|
||||
def run(self):
|
||||
|
||||
bld = self.inputs[0].__class__.ctx
|
||||
|
||||
get = self.env.get_flat
|
||||
cmd1 = "%s %s --prefix=%s --header > %s" % (
|
||||
get('GLIB_GENMARSHAL'),
|
||||
self.inputs[0].srcpath(),
|
||||
get('GLIB_GENMARSHAL_PREFIX'),
|
||||
self.outputs[0].abspath()
|
||||
)
|
||||
|
||||
ret = bld.exec_command(cmd1)
|
||||
if ret: return ret
|
||||
|
||||
#print self.outputs[1].abspath()
|
||||
c = '''#include "%s"\n''' % self.outputs[0].name
|
||||
self.outputs[1].write(c)
|
||||
|
||||
cmd2 = "%s %s --prefix=%s --body >> %s" % (
|
||||
get('GLIB_GENMARSHAL'),
|
||||
self.inputs[0].srcpath(),
|
||||
get('GLIB_GENMARSHAL_PREFIX'),
|
||||
self.outputs[1].abspath()
|
||||
)
|
||||
return bld.exec_command(cmd2)
|
||||
|
||||
vars = ['GLIB_GENMARSHAL_PREFIX', 'GLIB_GENMARSHAL']
|
||||
color = 'BLUE'
|
||||
ext_out = ['.h']
|
||||
|
||||
########################## glib-mkenums
|
||||
|
||||
@taskgen_method
|
||||
def add_enums_from_template(self, source='', target='', template='', comments=''):
|
||||
"""
|
||||
Add a file to the list of enum files to process. Store them in the attribute *enums_list*.
|
||||
|
||||
:param source: enum file to process
|
||||
:type source: string
|
||||
:param target: target file
|
||||
:type target: string
|
||||
:param template: template file
|
||||
:type template: string
|
||||
:param comments: comments
|
||||
:type comments: string
|
||||
"""
|
||||
if not hasattr(self, 'enums_list'):
|
||||
self.enums_list = []
|
||||
self.meths.append('process_enums')
|
||||
self.enums_list.append({'source': source,
|
||||
'target': target,
|
||||
'template': template,
|
||||
'file-head': '',
|
||||
'file-prod': '',
|
||||
'file-tail': '',
|
||||
'enum-prod': '',
|
||||
'value-head': '',
|
||||
'value-prod': '',
|
||||
'value-tail': '',
|
||||
'comments': comments})
|
||||
|
||||
@taskgen_method
|
||||
def add_enums(self, source='', target='',
|
||||
file_head='', file_prod='', file_tail='', enum_prod='',
|
||||
value_head='', value_prod='', value_tail='', comments=''):
|
||||
"""
|
||||
Add a file to the list of enum files to process. Store them in the attribute *enums_list*.
|
||||
|
||||
:param source: enum file to process
|
||||
:type source: string
|
||||
:param target: target file
|
||||
:type target: string
|
||||
:param file_head: unused
|
||||
:param file_prod: unused
|
||||
:param file_tail: unused
|
||||
:param enum_prod: unused
|
||||
:param value_head: unused
|
||||
:param value_prod: unused
|
||||
:param value_tail: unused
|
||||
:param comments: comments
|
||||
:type comments: string
|
||||
"""
|
||||
if not hasattr(self, 'enums_list'):
|
||||
self.enums_list = []
|
||||
self.meths.append('process_enums')
|
||||
self.enums_list.append({'source': source,
|
||||
'template': '',
|
||||
'target': target,
|
||||
'file-head': file_head,
|
||||
'file-prod': file_prod,
|
||||
'file-tail': file_tail,
|
||||
'enum-prod': enum_prod,
|
||||
'value-head': value_head,
|
||||
'value-prod': value_prod,
|
||||
'value-tail': value_tail,
|
||||
'comments': comments})
|
||||
|
||||
@before_method('process_source')
|
||||
def process_enums(self):
|
||||
"""
|
||||
Process the enum files stored in the attribute *enum_list* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances.
|
||||
"""
|
||||
for enum in getattr(self, 'enums_list', []):
|
||||
task = self.create_task('glib_mkenums')
|
||||
env = task.env
|
||||
|
||||
inputs = []
|
||||
|
||||
# process the source
|
||||
source_list = self.to_list(enum['source'])
|
||||
if not source_list:
|
||||
raise Errors.WafError('missing source ' + str(enum))
|
||||
source_list = [self.path.find_resource(k) for k in source_list]
|
||||
inputs += source_list
|
||||
env['GLIB_MKENUMS_SOURCE'] = [k.abspath() for k in source_list]
|
||||
|
||||
# find the target
|
||||
if not enum['target']:
|
||||
raise Errors.WafError('missing target ' + str(enum))
|
||||
tgt_node = self.path.find_or_declare(enum['target'])
|
||||
if tgt_node.name.endswith('.c'):
|
||||
self.source.append(tgt_node)
|
||||
env['GLIB_MKENUMS_TARGET'] = tgt_node.abspath()
|
||||
|
||||
|
||||
options = []
|
||||
|
||||
if enum['template']: # template, if provided
|
||||
template_node = self.path.find_resource(enum['template'])
|
||||
options.append('--template %s' % (template_node.abspath()))
|
||||
inputs.append(template_node)
|
||||
params = {'file-head' : '--fhead',
|
||||
'file-prod' : '--fprod',
|
||||
'file-tail' : '--ftail',
|
||||
'enum-prod' : '--eprod',
|
||||
'value-head' : '--vhead',
|
||||
'value-prod' : '--vprod',
|
||||
'value-tail' : '--vtail',
|
||||
'comments': '--comments'}
|
||||
for param, option in params.items():
|
||||
if enum[param]:
|
||||
options.append('%s %r' % (option, enum[param]))
|
||||
|
||||
env['GLIB_MKENUMS_OPTIONS'] = ' '.join(options)
|
||||
|
||||
# update the task instance
|
||||
task.set_inputs(inputs)
|
||||
task.set_outputs(tgt_node)
|
||||
|
||||
class glib_mkenums(Task.Task):
|
||||
"""
|
||||
Process enum files
|
||||
"""
|
||||
run_str = '${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}'
|
||||
color = 'PINK'
|
||||
ext_out = ['.h']
|
||||
|
||||
######################################### gsettings
|
||||
|
||||
@taskgen_method
|
||||
def add_settings_schemas(self, filename_list):
|
||||
"""
|
||||
Add settings files to process, add them to *settings_schema_files*
|
||||
|
||||
:param filename_list: files
|
||||
:type filename_list: list of string
|
||||
"""
|
||||
if not hasattr(self, 'settings_schema_files'):
|
||||
self.settings_schema_files = []
|
||||
|
||||
if not isinstance(filename_list, list):
|
||||
filename_list = [filename_list]
|
||||
|
||||
self.settings_schema_files.extend(filename_list)
|
||||
|
||||
@taskgen_method
|
||||
def add_settings_enums(self, namespace, filename_list):
|
||||
"""
|
||||
This function may be called only once by task generator to set the enums namespace.
|
||||
|
||||
:param namespace: namespace
|
||||
:type namespace: string
|
||||
:param filename_list: enum files to process
|
||||
:type filename_list: file list
|
||||
"""
|
||||
if hasattr(self, 'settings_enum_namespace'):
|
||||
raise Errors.WafError("Tried to add gsettings enums to '%s' more than once" % self.name)
|
||||
self.settings_enum_namespace = namespace
|
||||
|
||||
if type(filename_list) != 'list':
|
||||
filename_list = [filename_list]
|
||||
self.settings_enum_files = filename_list
|
||||
|
||||
|
||||
def r_change_ext(self, ext):
|
||||
"""
|
||||
Change the extension from the *last* dot in the filename. The gsettings schemas
|
||||
often have names of the form org.gsettings.test.gschema.xml
|
||||
"""
|
||||
name = self.name
|
||||
k = name.rfind('.')
|
||||
if k >= 0:
|
||||
name = name[:k] + ext
|
||||
else:
|
||||
name = name + ext
|
||||
return self.parent.find_or_declare([name])
|
||||
|
||||
@feature('glib2')
|
||||
def process_settings(self):
|
||||
"""
|
||||
Process the schema files in *settings_schema_files* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances. The
|
||||
same files are validated through :py:class:`waflib.Tools.glib2.glib_validate_schema` tasks.
|
||||
|
||||
"""
|
||||
enums_tgt_node = []
|
||||
install_files = []
|
||||
|
||||
settings_schema_files = getattr(self, 'settings_schema_files', [])
|
||||
if settings_schema_files and not self.env['GLIB_COMPILE_SCHEMAS']:
|
||||
raise Errors.WafError ("Unable to process GSettings schemas - glib-compile-schemas was not found during configure")
|
||||
|
||||
# 1. process gsettings_enum_files (generate .enums.xml)
|
||||
#
|
||||
if hasattr(self, 'settings_enum_files'):
|
||||
enums_task = self.create_task('glib_mkenums')
|
||||
|
||||
source_list = self.settings_enum_files
|
||||
source_list = [self.path.find_resource(k) for k in source_list]
|
||||
enums_task.set_inputs(source_list)
|
||||
enums_task.env['GLIB_MKENUMS_SOURCE'] = [k.abspath() for k in source_list]
|
||||
|
||||
target = self.settings_enum_namespace + '.enums.xml'
|
||||
tgt_node = self.path.find_or_declare(target)
|
||||
enums_task.set_outputs(tgt_node)
|
||||
enums_task.env['GLIB_MKENUMS_TARGET'] = tgt_node.abspath()
|
||||
enums_tgt_node = [tgt_node]
|
||||
|
||||
install_files.append (tgt_node)
|
||||
|
||||
options = '--comments "<!-- @comment@ -->" --fhead "<schemalist>" --vhead " <@type@ id=\\"%s.@EnumName@\\">" --vprod " <value nick=\\"@valuenick@\\" value=\\"@valuenum@\\"/>" --vtail " </@type@>" --ftail "</schemalist>" ' % (self.settings_enum_namespace)
|
||||
enums_task.env['GLIB_MKENUMS_OPTIONS'] = options
|
||||
|
||||
# 2. process gsettings_schema_files (validate .gschema.xml files)
|
||||
#
|
||||
for schema in settings_schema_files:
|
||||
schema_task = self.create_task ('glib_validate_schema')
|
||||
|
||||
schema_node = self.path.find_resource(schema)
|
||||
if not schema_node:
|
||||
raise Errors.WafError("Cannot find the schema file '%s'" % schema)
|
||||
install_files.append(schema_node)
|
||||
source_list = enums_tgt_node + [schema_node]
|
||||
|
||||
schema_task.set_inputs (source_list)
|
||||
schema_task.env['GLIB_COMPILE_SCHEMAS_OPTIONS'] = [("--schema-file=" + k.abspath()) for k in source_list]
|
||||
|
||||
target_node = r_change_ext (schema_node, '.xml.valid')
|
||||
schema_task.set_outputs (target_node)
|
||||
schema_task.env['GLIB_VALIDATE_SCHEMA_OUTPUT'] = target_node.abspath()
|
||||
|
||||
# 3. schemas install task
|
||||
def compile_schemas_callback(bld):
|
||||
if not bld.is_install: return
|
||||
Logs.pprint ('YELLOW','Updating GSettings schema cache')
|
||||
command = Utils.subst_vars("${GLIB_COMPILE_SCHEMAS} ${GSETTINGSSCHEMADIR}", bld.env)
|
||||
ret = self.bld.exec_command(command)
|
||||
|
||||
if self.bld.is_install:
|
||||
if not self.env['GSETTINGSSCHEMADIR']:
|
||||
raise Errors.WafError ('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)')
|
||||
|
||||
if install_files:
|
||||
self.bld.install_files (self.env['GSETTINGSSCHEMADIR'], install_files)
|
||||
|
||||
if not hasattr(self.bld, '_compile_schemas_registered'):
|
||||
self.bld.add_post_fun (compile_schemas_callback)
|
||||
self.bld._compile_schemas_registered = True
|
||||
|
||||
class glib_validate_schema(Task.Task):
|
||||
"""
|
||||
Validate schema files
|
||||
"""
|
||||
run_str = 'rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}'
|
||||
color = 'PINK'
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Find the following programs:
|
||||
|
||||
* *glib-genmarshal* and set *GLIB_GENMARSHAL*
|
||||
* *glib-mkenums* and set *GLIB_MKENUMS*
|
||||
* *glib-compile-schemas* and set *GLIB_COMPILE_SCHEMAS* (not mandatory)
|
||||
|
||||
And set the variable *GSETTINGSSCHEMADIR*
|
||||
"""
|
||||
conf.find_program('glib-genmarshal', var='GLIB_GENMARSHAL')
|
||||
conf.find_perl_program('glib-mkenums', var='GLIB_MKENUMS')
|
||||
|
||||
# when cross-compiling, gsettings.m4 locates the program with the following:
|
||||
# pkg-config --variable glib_compile_schemas gio-2.0
|
||||
conf.find_program('glib-compile-schemas', var='GLIB_COMPILE_SCHEMAS', mandatory=False)
|
||||
|
||||
def getstr(varname):
|
||||
return getattr(Options.options, varname, getattr(conf.env,varname, ''))
|
||||
|
||||
# TODO make this dependent on the gnu_dirs tool?
|
||||
gsettingsschemadir = getstr('GSETTINGSSCHEMADIR')
|
||||
if not gsettingsschemadir:
|
||||
datadir = getstr('DATADIR')
|
||||
if not datadir:
|
||||
prefix = conf.env['PREFIX']
|
||||
datadir = os.path.join(prefix, 'share')
|
||||
gsettingsschemadir = os.path.join(datadir, 'glib-2.0', 'schemas')
|
||||
|
||||
conf.env['GSETTINGSSCHEMADIR'] = gsettingsschemadir
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add the ``--gsettingsschemadir`` command-line option
|
||||
"""
|
||||
opt.add_option('--gsettingsschemadir', help='GSettings schema location [Default: ${datadir}/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR')
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Ali Sabil, 2007
|
||||
|
||||
"""
|
||||
Sets various standard variables such as INCLUDEDIR. SBINDIR and others. To use this module just call::
|
||||
|
||||
opt.load('gnu_dirs')
|
||||
|
||||
and::
|
||||
|
||||
conf.load('gnu_dirs')
|
||||
|
||||
Add options for the standard GNU directories, this tool will add the options
|
||||
found in autotools, and will update the environment with the following
|
||||
installation variables:
|
||||
|
||||
============== ========================================= =======================
|
||||
Variable Description Value
|
||||
============== ========================================= =======================
|
||||
PREFIX architecture-independent files /usr/local
|
||||
EXEC_PREFIX architecture-dependent files PREFIX
|
||||
BINDIR user executables EXEC_PREFIX/bin
|
||||
SBINDIR user executables EXEC_PREFIX/sbin
|
||||
LIBEXECDIR program executables EXEC_PREFIX/libexec
|
||||
SYSCONFDIR read-only single-machine data PREFIX/etc
|
||||
SHAREDSTATEDIR modifiable architecture-independent data PREFIX/com
|
||||
LOCALSTATEDIR modifiable single-machine data PREFIX/var
|
||||
LIBDIR object code libraries EXEC_PREFIX/lib
|
||||
INCLUDEDIR C header files PREFIX/include
|
||||
OLDINCLUDEDIR C header files for non-gcc /usr/include
|
||||
DATAROOTDIR read-only arch.-independent data root PREFIX/share
|
||||
DATADIR read-only architecture-independent data DATAROOTDIR
|
||||
INFODIR info documentation DATAROOTDIR/info
|
||||
LOCALEDIR locale-dependent data DATAROOTDIR/locale
|
||||
MANDIR man documentation DATAROOTDIR/man
|
||||
DOCDIR documentation root DATAROOTDIR/doc/APPNAME
|
||||
HTMLDIR html documentation DOCDIR
|
||||
DVIDIR dvi documentation DOCDIR
|
||||
PDFDIR pdf documentation DOCDIR
|
||||
PSDIR ps documentation DOCDIR
|
||||
============== ========================================= =======================
|
||||
"""
|
||||
|
||||
import os
|
||||
from waflib import Utils, Options, Context
|
||||
|
||||
_options = [x.split(', ') for x in '''
|
||||
bindir, user executables, ${EXEC_PREFIX}/bin
|
||||
sbindir, system admin executables, ${EXEC_PREFIX}/sbin
|
||||
libexecdir, program executables, ${EXEC_PREFIX}/libexec
|
||||
sysconfdir, read-only single-machine data, ${PREFIX}/etc
|
||||
sharedstatedir, modifiable architecture-independent data, ${PREFIX}/com
|
||||
localstatedir, modifiable single-machine data, ${PREFIX}/var
|
||||
libdir, object code libraries, ${EXEC_PREFIX}/lib
|
||||
includedir, C header files, ${PREFIX}/include
|
||||
oldincludedir, C header files for non-gcc, /usr/include
|
||||
datarootdir, read-only arch.-independent data root, ${PREFIX}/share
|
||||
datadir, read-only architecture-independent data, ${DATAROOTDIR}
|
||||
infodir, info documentation, ${DATAROOTDIR}/info
|
||||
localedir, locale-dependent data, ${DATAROOTDIR}/locale
|
||||
mandir, man documentation, ${DATAROOTDIR}/man
|
||||
docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE}
|
||||
htmldir, html documentation, ${DOCDIR}
|
||||
dvidir, dvi documentation, ${DOCDIR}
|
||||
pdfdir, pdf documentation, ${DOCDIR}
|
||||
psdir, ps documentation, ${DOCDIR}
|
||||
'''.split('\n') if x]
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Read the command-line options to set lots of variables in *conf.env*. The variables
|
||||
BINDIR and LIBDIR will be overwritten.
|
||||
"""
|
||||
def get_param(varname, default):
|
||||
return getattr(Options.options, varname, '') or default
|
||||
|
||||
env = conf.env
|
||||
env.LIBDIR = env.BINDIR = []
|
||||
env.EXEC_PREFIX = get_param('EXEC_PREFIX', env.PREFIX)
|
||||
env.PACKAGE = getattr(Context.g_module, 'APPNAME', None) or env.PACKAGE
|
||||
|
||||
complete = False
|
||||
iter = 0
|
||||
while not complete and iter < len(_options) + 1:
|
||||
iter += 1
|
||||
complete = True
|
||||
for name, help, default in _options:
|
||||
name = name.upper()
|
||||
if not env[name]:
|
||||
try:
|
||||
env[name] = Utils.subst_vars(get_param(name, default).replace('/', os.sep), env)
|
||||
except TypeError:
|
||||
complete = False
|
||||
|
||||
if not complete:
|
||||
lst = [name for name, _, _ in _options if not env[name.upper()]]
|
||||
raise conf.errors.WafError('Variable substitution failure %r' % lst)
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add lots of command-line options, for example::
|
||||
|
||||
--exec-prefix: EXEC_PREFIX
|
||||
"""
|
||||
inst_dir = opt.add_option_group('Installation directories',
|
||||
'By default, "waf install" will put the files in\
|
||||
"/usr/local/bin", "/usr/local/lib" etc. An installation prefix other\
|
||||
than "/usr/local" can be given using "--prefix", for example "--prefix=$HOME"')
|
||||
|
||||
for k in ('--prefix', '--destdir'):
|
||||
option = opt.parser.get_option(k)
|
||||
if option:
|
||||
opt.parser.remove_option(k)
|
||||
inst_dir.add_option(option)
|
||||
|
||||
inst_dir.add_option('--exec-prefix',
|
||||
help = 'installation prefix [Default: ${PREFIX}]',
|
||||
default = '',
|
||||
dest = 'EXEC_PREFIX')
|
||||
|
||||
dirs_options = opt.add_option_group('Pre-defined installation directories', '')
|
||||
|
||||
for name, help, default in _options:
|
||||
option_name = '--' + name
|
||||
str_default = default
|
||||
str_help = '%s [Default: %s]' % (help, str_default)
|
||||
dirs_options.add_option(option_name, help=str_help, default='', dest=name.upper())
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
# Yinon Ehrlich, 2009
|
||||
|
||||
"""
|
||||
g++/llvm detection.
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib import Configure, Options, Utils
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_gxx(conf):
|
||||
"""
|
||||
Find the program g++, and if present, try to detect its version number
|
||||
"""
|
||||
cxx = conf.find_program(['g++', 'c++'], var='CXX')
|
||||
cxx = conf.cmd_to_list(cxx)
|
||||
conf.get_cc_version(cxx, gcc=True)
|
||||
conf.env.CXX_NAME = 'gcc'
|
||||
conf.env.CXX = cxx
|
||||
|
||||
@conf
|
||||
def gxx_common_flags(conf):
|
||||
"""
|
||||
Common flags for g++ on nearly all platforms
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['CXX_SRC_F'] = []
|
||||
v['CXX_TGT_F'] = ['-c', '-o']
|
||||
|
||||
# linker
|
||||
if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']
|
||||
v['CXXLNK_SRC_F'] = []
|
||||
v['CXXLNK_TGT_F'] = ['-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
v['RPATH_ST'] = '-Wl,-rpath,%s'
|
||||
|
||||
v['SONAME_ST'] = '-Wl,-h,%s'
|
||||
v['SHLIB_MARKER'] = '-Wl,-Bdynamic'
|
||||
v['STLIB_MARKER'] = '-Wl,-Bstatic'
|
||||
|
||||
# program
|
||||
v['cxxprogram_PATTERN'] = '%s'
|
||||
|
||||
# shared library
|
||||
v['CXXFLAGS_cxxshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_cxxshlib'] = ['-shared']
|
||||
v['cxxshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
# static lib
|
||||
v['LINKFLAGS_cxxstlib'] = ['-Wl,-Bstatic']
|
||||
v['cxxstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
# osx stuff
|
||||
v['LINKFLAGS_MACBUNDLE'] = ['-bundle', '-undefined', 'dynamic_lookup']
|
||||
v['CXXFLAGS_MACBUNDLE'] = ['-fPIC']
|
||||
v['macbundle_PATTERN'] = '%s.bundle'
|
||||
|
||||
@conf
|
||||
def gxx_modifier_win32(conf):
|
||||
"""Configuration flags for executing gcc on Windows"""
|
||||
v = conf.env
|
||||
v['cxxprogram_PATTERN'] = '%s.exe'
|
||||
|
||||
v['cxxshlib_PATTERN'] = '%s.dll'
|
||||
v['implib_PATTERN'] = 'lib%s.dll.a'
|
||||
v['IMPLIB_ST'] = '-Wl,--out-implib,%s'
|
||||
|
||||
v['CXXFLAGS_cxxshlib'] = []
|
||||
|
||||
# Auto-import is enabled by default even without this option,
|
||||
# but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages
|
||||
# that the linker emits otherwise.
|
||||
v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])
|
||||
|
||||
@conf
|
||||
def gxx_modifier_cygwin(conf):
|
||||
"""Configuration flags for executing g++ on Cygwin"""
|
||||
gxx_modifier_win32(conf)
|
||||
v = conf.env
|
||||
v['cxxshlib_PATTERN'] = 'cyg%s.dll'
|
||||
v.append_value('LINKFLAGS_cxxshlib', ['-Wl,--enable-auto-image-base'])
|
||||
v['CXXFLAGS_cxxshlib'] = []
|
||||
|
||||
@conf
|
||||
def gxx_modifier_darwin(conf):
|
||||
"""Configuration flags for executing g++ on MacOS"""
|
||||
v = conf.env
|
||||
v['CXXFLAGS_cxxshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_cxxshlib'] = ['-dynamiclib', '-Wl,-compatibility_version,1', '-Wl,-current_version,1']
|
||||
v['cxxshlib_PATTERN'] = 'lib%s.dylib'
|
||||
v['FRAMEWORKPATH_ST'] = '-F%s'
|
||||
v['FRAMEWORK_ST'] = ['-framework']
|
||||
v['ARCH_ST'] = ['-arch']
|
||||
|
||||
v['LINKFLAGS_cxxstlib'] = []
|
||||
|
||||
v['SHLIB_MARKER'] = []
|
||||
v['STLIB_MARKER'] = []
|
||||
v['SONAME_ST'] = []
|
||||
|
||||
@conf
|
||||
def gxx_modifier_aix(conf):
|
||||
"""Configuration flags for executing g++ on AIX"""
|
||||
v = conf.env
|
||||
v['LINKFLAGS_cxxprogram']= ['-Wl,-brtl']
|
||||
|
||||
v['LINKFLAGS_cxxshlib'] = ['-shared', '-Wl,-brtl,-bexpfull']
|
||||
v['SHLIB_MARKER'] = []
|
||||
|
||||
@conf
|
||||
def gxx_modifier_hpux(conf):
|
||||
v = conf.env
|
||||
v['SHLIB_MARKER'] = []
|
||||
v['STLIB_MARKER'] = '-Bstatic'
|
||||
v['CFLAGS_cxxshlib'] = ['-fPIC','-DPIC']
|
||||
v['cxxshlib_PATTERN'] = 'lib%s.sl'
|
||||
|
||||
@conf
|
||||
def gxx_modifier_platform(conf):
|
||||
"""Execute platform-specific functions based on *gxx_modifier_+NAME*"""
|
||||
# * set configurations specific for a platform.
|
||||
# * the destination platform is detected automatically by looking at the macros the compiler predefines,
|
||||
# and if it's not recognised, it fallbacks to sys.platform.
|
||||
gxx_modifier_func = getattr(conf, 'gxx_modifier_' + conf.env.DEST_OS, None)
|
||||
if gxx_modifier_func:
|
||||
gxx_modifier_func()
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Configuration for g++
|
||||
"""
|
||||
conf.find_gxx()
|
||||
conf.find_ar()
|
||||
conf.gxx_common_flags()
|
||||
conf.gxx_modifier_platform()
|
||||
conf.cxx_load_tools()
|
||||
conf.cxx_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Stian Selnes, 2008
|
||||
# Thomas Nagy 2009-2010 (ita)
|
||||
|
||||
"""
|
||||
Detect the Intel C compiler
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib.Tools import ccroot, ar, gcc
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_icc(conf):
|
||||
"""
|
||||
Find the program icc and execute it to ensure it really is icc
|
||||
"""
|
||||
if sys.platform == 'cygwin':
|
||||
conf.fatal('The Intel compiler does not work on Cygwin')
|
||||
|
||||
v = conf.env
|
||||
cc = None
|
||||
if v['CC']: cc = v['CC']
|
||||
elif 'CC' in conf.environ: cc = conf.environ['CC']
|
||||
if not cc: cc = conf.find_program('icc', var='CC')
|
||||
if not cc: cc = conf.find_program('ICL', var='CC')
|
||||
if not cc: conf.fatal('Intel C Compiler (icc) was not found')
|
||||
cc = conf.cmd_to_list(cc)
|
||||
|
||||
conf.get_cc_version(cc, icc=True)
|
||||
v['CC'] = cc
|
||||
v['CC_NAME'] = 'icc'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_icc()
|
||||
conf.find_ar()
|
||||
conf.gcc_common_flags()
|
||||
conf.gcc_modifier_platform()
|
||||
conf.cc_load_tools()
|
||||
conf.cc_add_flags()
|
||||
conf.link_add_flags()
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy 2009-2010 (ita)
|
||||
|
||||
"""
|
||||
Detect the Intel C++ compiler
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib.Tools import ccroot, ar, gxx
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_icpc(conf):
|
||||
"""
|
||||
Find the program icpc, and execute it to ensure it really is icpc
|
||||
"""
|
||||
if sys.platform == 'cygwin':
|
||||
conf.fatal('The Intel compiler does not work on Cygwin')
|
||||
|
||||
v = conf.env
|
||||
cxx = None
|
||||
if v['CXX']: cxx = v['CXX']
|
||||
elif 'CXX' in conf.environ: cxx = conf.environ['CXX']
|
||||
if not cxx: cxx = conf.find_program('icpc', var='CXX')
|
||||
if not cxx: conf.fatal('Intel C++ Compiler (icpc) was not found')
|
||||
cxx = conf.cmd_to_list(cxx)
|
||||
|
||||
conf.get_cc_version(cxx, icc=True)
|
||||
v['CXX'] = cxx
|
||||
v['CXX_NAME'] = 'icc'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_icpc()
|
||||
conf.find_ar()
|
||||
conf.gxx_common_flags()
|
||||
conf.gxx_modifier_platform()
|
||||
conf.cxx_load_tools()
|
||||
conf.cxx_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# DC 2008
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
import re
|
||||
from waflib import Utils
|
||||
from waflib.Tools import fc, fc_config, fc_scan, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_ifort(conf):
|
||||
fc = conf.find_program('ifort', var='FC')
|
||||
fc = conf.cmd_to_list(fc)
|
||||
conf.get_ifort_version(fc)
|
||||
conf.env.FC_NAME = 'IFORT'
|
||||
|
||||
@conf
|
||||
def ifort_modifier_cygwin(conf):
|
||||
raise NotImplementedError("Ifort on cygwin not yet implemented")
|
||||
|
||||
@conf
|
||||
def ifort_modifier_win32(conf):
|
||||
fc_config.fortran_modifier_win32(conf)
|
||||
|
||||
@conf
|
||||
def ifort_modifier_darwin(conf):
|
||||
fc_config.fortran_modifier_darwin(conf)
|
||||
|
||||
@conf
|
||||
def ifort_modifier_platform(conf):
|
||||
dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
|
||||
ifort_modifier_func = getattr(conf, 'ifort_modifier_' + dest_os, None)
|
||||
if ifort_modifier_func:
|
||||
ifort_modifier_func()
|
||||
|
||||
@conf
|
||||
def get_ifort_version(conf, fc):
|
||||
"""get the compiler version"""
|
||||
|
||||
version_re = re.compile(r"ifort\s*\(IFORT\)\s*(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
|
||||
cmd = fc + ['--version']
|
||||
out, err = fc_config.getoutput(conf, cmd, stdin=False)
|
||||
if out:
|
||||
match = version_re(out)
|
||||
else:
|
||||
match = version_re(err)
|
||||
if not match:
|
||||
conf.fatal('cannot determine ifort version.')
|
||||
k = match.groupdict()
|
||||
conf.env['FC_VERSION'] = (k['major'], k['minor'])
|
||||
|
||||
def configure(conf):
|
||||
conf.find_ifort()
|
||||
conf.find_program('xiar', var='AR')
|
||||
conf.env.ARFLAGS = 'rcs'
|
||||
conf.fc_flags()
|
||||
conf.fc_add_flags()
|
||||
conf.ifort_modifier_platform()
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
Support for translation tools such as msgfmt and intltool
|
||||
|
||||
Usage::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('gnu_dirs intltool')
|
||||
|
||||
def build(bld):
|
||||
# process the .po files into .gmo files, and install them in LOCALEDIR
|
||||
bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}")
|
||||
|
||||
# process an input file, substituting the translations from the po dir
|
||||
bld(
|
||||
features = "intltool_in",
|
||||
podir = "../po",
|
||||
flags = ["-d", "-q", "-u", "-c"],
|
||||
source = 'kupfer.desktop.in',
|
||||
install_path = "${DATADIR}/applications",
|
||||
)
|
||||
|
||||
Usage of the :py:mod:`waflib.Tools.gnu_dirs` is recommended, but not obligatory.
|
||||
"""
|
||||
|
||||
import os, re
|
||||
from waflib import Configure, TaskGen, Task, Utils, Runner, Options, Build, Logs
|
||||
import waflib.Tools.ccroot
|
||||
from waflib.TaskGen import feature, before_method
|
||||
from waflib.Logs import error
|
||||
|
||||
@before_method('process_source')
|
||||
@feature('intltool_in')
|
||||
def apply_intltool_in_f(self):
|
||||
"""
|
||||
Create tasks to translate files by intltool-merge::
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features = "intltool_in",
|
||||
podir = "../po",
|
||||
flags = ["-d", "-q", "-u", "-c"],
|
||||
source = 'kupfer.desktop.in',
|
||||
install_path = "${DATADIR}/applications",
|
||||
)
|
||||
|
||||
:param podir: location of the .po files
|
||||
:type podir: string
|
||||
:param source: source files to process
|
||||
:type source: list of string
|
||||
:param flags: compilation flags ("-quc" by default)
|
||||
:type flags: list of string
|
||||
:param install_path: installation path
|
||||
:type install_path: string
|
||||
"""
|
||||
try: self.meths.remove('process_source')
|
||||
except ValueError: pass
|
||||
|
||||
if not self.env.LOCALEDIR:
|
||||
self.env.LOCALEDIR = self.env.PREFIX + '/share/locale'
|
||||
|
||||
for i in self.to_list(self.source):
|
||||
node = self.path.find_resource(i)
|
||||
|
||||
podir = getattr(self, 'podir', 'po')
|
||||
podirnode = self.path.find_dir(podir)
|
||||
if not podirnode:
|
||||
error("could not find the podir %r" % podir)
|
||||
continue
|
||||
|
||||
cache = getattr(self, 'intlcache', '.intlcache')
|
||||
self.env['INTLCACHE'] = os.path.join(self.path.bldpath(), podir, cache)
|
||||
self.env['INTLPODIR'] = podirnode.bldpath()
|
||||
self.env['INTLFLAGS'] = getattr(self, 'flags', ['-q', '-u', '-c'])
|
||||
|
||||
task = self.create_task('intltool', node, node.change_ext(''))
|
||||
inst = getattr(self, 'install_path', '${LOCALEDIR}')
|
||||
if inst:
|
||||
self.bld.install_files(inst, task.outputs)
|
||||
|
||||
@feature('intltool_po')
|
||||
def apply_intltool_po(self):
|
||||
"""
|
||||
Create tasks to process po files::
|
||||
|
||||
def build(bld):
|
||||
bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}")
|
||||
|
||||
The relevant task generator arguments are:
|
||||
|
||||
:param podir: directory of the .po files
|
||||
:type podir: string
|
||||
:param appname: name of the application
|
||||
:type appname: string
|
||||
:param install_path: installation directory
|
||||
:type install_path: string
|
||||
|
||||
The file LINGUAS must be present in the directory pointed by *podir* and list the translation files to process.
|
||||
"""
|
||||
try: self.meths.remove('process_source')
|
||||
except ValueError: pass
|
||||
|
||||
if not self.env.LOCALEDIR:
|
||||
self.env.LOCALEDIR = self.env.PREFIX + '/share/locale'
|
||||
|
||||
appname = getattr(self, 'appname', 'set_your_app_name')
|
||||
podir = getattr(self, 'podir', '')
|
||||
inst = getattr(self, 'install_path', '${LOCALEDIR}')
|
||||
|
||||
linguas = self.path.find_node(os.path.join(podir, 'LINGUAS'))
|
||||
if linguas:
|
||||
# scan LINGUAS file for locales to process
|
||||
file = open(linguas.abspath())
|
||||
langs = []
|
||||
for line in file.readlines():
|
||||
# ignore lines containing comments
|
||||
if not line.startswith('#'):
|
||||
langs += line.split()
|
||||
file.close()
|
||||
re_linguas = re.compile('[-a-zA-Z_@.]+')
|
||||
for lang in langs:
|
||||
# Make sure that we only process lines which contain locales
|
||||
if re_linguas.match(lang):
|
||||
node = self.path.find_resource(os.path.join(podir, re_linguas.match(lang).group() + '.po'))
|
||||
task = self.create_task('po', node, node.change_ext('.mo'))
|
||||
|
||||
if inst:
|
||||
filename = task.outputs[0].name
|
||||
(langname, ext) = os.path.splitext(filename)
|
||||
inst_file = inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + appname + '.mo'
|
||||
self.bld.install_as(inst_file, task.outputs[0], chmod=getattr(self, 'chmod', Utils.O644), env=task.env)
|
||||
|
||||
else:
|
||||
Logs.pprint('RED', "Error no LINGUAS file found in po directory")
|
||||
|
||||
class po(Task.Task):
|
||||
"""
|
||||
Compile .po files into .gmo files
|
||||
"""
|
||||
run_str = '${MSGFMT} -o ${TGT} ${SRC}'
|
||||
color = 'BLUE'
|
||||
|
||||
class intltool(Task.Task):
|
||||
"""
|
||||
Let intltool-merge translate an input file
|
||||
"""
|
||||
run_str = '${INTLTOOL} ${INTLFLAGS} ${INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}'
|
||||
color = 'BLUE'
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the program *msgfmt* and set *conf.env.MSGFMT*.
|
||||
Detect the program *intltool-merge* and set *conf.env.INTLTOOL*.
|
||||
It is possible to set INTLTOOL in the environment, but it must not have spaces in it::
|
||||
|
||||
$ INTLTOOL="/path/to/the program/intltool" waf configure
|
||||
|
||||
If a C/C++ compiler is present, execute a compilation test to find the header *locale.h*.
|
||||
"""
|
||||
conf.find_program('msgfmt', var='MSGFMT')
|
||||
conf.find_perl_program('intltool-merge', var='INTLTOOL')
|
||||
|
||||
prefix = conf.env.PREFIX
|
||||
datadir = conf.env.DATADIR
|
||||
if not datadir:
|
||||
datadir = os.path.join(prefix,'share')
|
||||
|
||||
conf.define('LOCALEDIR', os.path.join(datadir, 'locale').replace('\\', '\\\\'))
|
||||
conf.define('DATADIR', datadir.replace('\\', '\\\\'))
|
||||
|
||||
if conf.env.CC or conf.env.CXX:
|
||||
conf.check(header_name='locale.h')
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#! /usr/bin/env python
|
||||
# imported from samba
|
||||
|
||||
"""
|
||||
compiler definition for irix/MIPSpro cc compiler
|
||||
based on suncc.py from waf
|
||||
"""
|
||||
|
||||
import os
|
||||
from waflib import Utils
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_irixcc(conf):
|
||||
v = conf.env
|
||||
cc = None
|
||||
if v['CC']: cc = v['CC']
|
||||
elif 'CC' in conf.environ: cc = conf.environ['CC']
|
||||
if not cc: cc = conf.find_program('cc', var='CC')
|
||||
if not cc: conf.fatal('irixcc was not found')
|
||||
cc = conf.cmd_to_list(cc)
|
||||
|
||||
try:
|
||||
conf.cmd_and_log(cc + ['-version'])
|
||||
except Exception:
|
||||
conf.fatal('%r -version could not be executed' % cc)
|
||||
|
||||
v['CC'] = cc
|
||||
v['CC_NAME'] = 'irix'
|
||||
|
||||
@conf
|
||||
def irixcc_common_flags(conf):
|
||||
v = conf.env
|
||||
|
||||
v['CC_SRC_F'] = ''
|
||||
v['CC_TGT_F'] = ['-c', '-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
# linker
|
||||
if not v['LINK_CC']: v['LINK_CC'] = v['CC']
|
||||
v['CCLNK_SRC_F'] = ''
|
||||
v['CCLNK_TGT_F'] = ['-o']
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
|
||||
v['cprogram_PATTERN'] = '%s'
|
||||
v['cshlib_PATTERN'] = 'lib%s.so'
|
||||
v['cstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_irixcc()
|
||||
conf.find_cpp()
|
||||
conf.find_ar()
|
||||
conf.irixcc_common_flags()
|
||||
conf.cc_load_tools()
|
||||
conf.cc_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
+480
@@ -0,0 +1,480 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
Java support
|
||||
|
||||
Javac is one of the few compilers that behaves very badly:
|
||||
|
||||
#. it outputs files where it wants to (-d is only for the package root)
|
||||
|
||||
#. it recompiles files silently behind your back
|
||||
|
||||
#. it outputs an undefined amount of files (inner classes)
|
||||
|
||||
Remember that the compilation can be performed using Jython[1] rather than regular Python. Instead of
|
||||
running one of the following commands::
|
||||
|
||||
./waf configure
|
||||
python waf configure
|
||||
|
||||
You would have to run::
|
||||
|
||||
java -jar /path/to/jython.jar waf configure
|
||||
|
||||
[1] http://www.jython.org/
|
||||
"""
|
||||
|
||||
import os, re, tempfile, shutil
|
||||
from waflib import TaskGen, Task, Utils, Options, Build, Errors, Node, Logs
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, before_method, after_method
|
||||
|
||||
from waflib.Tools import ccroot
|
||||
ccroot.USELIB_VARS['javac'] = set(['CLASSPATH', 'JAVACFLAGS'])
|
||||
|
||||
|
||||
SOURCE_RE = '**/*.java'
|
||||
JAR_RE = '**/*'
|
||||
|
||||
class_check_source = '''
|
||||
public class Test {
|
||||
public static void main(String[] argv) {
|
||||
Class lib;
|
||||
if (argv.length < 1) {
|
||||
System.err.println("Missing argument");
|
||||
System.exit(77);
|
||||
}
|
||||
try {
|
||||
lib = Class.forName(argv[0]);
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("ClassNotFoundException");
|
||||
System.exit(1);
|
||||
}
|
||||
lib = null;
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
@feature('javac')
|
||||
@before_method('process_source')
|
||||
def apply_java(self):
|
||||
"""
|
||||
Create a javac task for compiling *.java files*. There can be
|
||||
only one javac task by task generator.
|
||||
"""
|
||||
Utils.def_attrs(self, jarname='', classpath='',
|
||||
sourcepath='.', srcdir='.',
|
||||
jar_mf_attributes={}, jar_mf_classpath=[])
|
||||
|
||||
nodes_lst = []
|
||||
|
||||
outdir = getattr(self, 'outdir', None)
|
||||
if outdir:
|
||||
if not isinstance(outdir, Node.Node):
|
||||
outdir = self.path.get_bld().make_node(self.outdir)
|
||||
else:
|
||||
outdir = self.path.get_bld()
|
||||
outdir.mkdir()
|
||||
self.outdir = outdir
|
||||
self.env['OUTDIR'] = outdir.abspath()
|
||||
|
||||
self.javac_task = tsk = self.create_task('javac')
|
||||
tmp = []
|
||||
|
||||
srcdir = getattr(self, 'srcdir', '')
|
||||
if isinstance(srcdir, Node.Node):
|
||||
srcdir = [srcdir]
|
||||
for x in Utils.to_list(srcdir):
|
||||
if isinstance(x, Node.Node):
|
||||
y = x
|
||||
else:
|
||||
y = self.path.find_dir(x)
|
||||
if not y:
|
||||
self.bld.fatal('Could not find the folder %s from %s' % (x, self.path))
|
||||
tmp.append(y)
|
||||
tsk.srcdir = tmp
|
||||
|
||||
if getattr(self, 'compat', None):
|
||||
tsk.env.append_value('JAVACFLAGS', ['-source', self.compat])
|
||||
|
||||
if hasattr(self, 'sourcepath'):
|
||||
fold = [isinstance(x, Node.Node) and x or self.path.find_dir(x) for x in self.to_list(self.sourcepath)]
|
||||
names = os.pathsep.join([x.srcpath() for x in fold])
|
||||
else:
|
||||
names = [x.srcpath() for x in tsk.srcdir]
|
||||
|
||||
if names:
|
||||
tsk.env.append_value('JAVACFLAGS', ['-sourcepath', names])
|
||||
|
||||
@feature('javac')
|
||||
@after_method('apply_java')
|
||||
def use_javac_files(self):
|
||||
"""
|
||||
Process the *use* attribute referring to other java compilations
|
||||
"""
|
||||
lst = []
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
names = self.to_list(getattr(self, 'use', []))
|
||||
get = self.bld.get_tgen_by_name
|
||||
for x in names:
|
||||
try:
|
||||
y = get(x)
|
||||
except Exception:
|
||||
self.uselib.append(x)
|
||||
else:
|
||||
y.post()
|
||||
lst.append(y.jar_task.outputs[0].abspath())
|
||||
self.javac_task.set_run_after(y.jar_task)
|
||||
|
||||
if lst:
|
||||
self.env.append_value('CLASSPATH', lst)
|
||||
|
||||
@feature('javac')
|
||||
@after_method('apply_java', 'propagate_uselib_vars', 'use_javac_files')
|
||||
def set_classpath(self):
|
||||
"""
|
||||
Set the CLASSPATH value on the *javac* task previously created.
|
||||
"""
|
||||
self.env.append_value('CLASSPATH', getattr(self, 'classpath', []))
|
||||
for x in self.tasks:
|
||||
x.env.CLASSPATH = os.pathsep.join(self.env.CLASSPATH) + os.pathsep
|
||||
|
||||
@feature('jar')
|
||||
@after_method('apply_java', 'use_javac_files')
|
||||
@before_method('process_source')
|
||||
def jar_files(self):
|
||||
"""
|
||||
Create a jar task. There can be only one jar task by task generator.
|
||||
"""
|
||||
destfile = getattr(self, 'destfile', 'test.jar')
|
||||
jaropts = getattr(self, 'jaropts', [])
|
||||
manifest = getattr(self, 'manifest', None)
|
||||
|
||||
basedir = getattr(self, 'basedir', None)
|
||||
if basedir:
|
||||
if not isinstance(self.basedir, Node.Node):
|
||||
basedir = self.path.get_bld().make_node(basedir)
|
||||
else:
|
||||
basedir = self.path.get_bld()
|
||||
if not basedir:
|
||||
self.bld.fatal('Could not find the basedir %r for %r' % (self.basedir, self))
|
||||
|
||||
self.jar_task = tsk = self.create_task('jar_create')
|
||||
if manifest:
|
||||
jarcreate = getattr(self, 'jarcreate', 'cfm')
|
||||
node = self.path.find_node(manifest)
|
||||
tsk.dep_nodes.append(node)
|
||||
jaropts.insert(0, node.abspath())
|
||||
else:
|
||||
jarcreate = getattr(self, 'jarcreate', 'cf')
|
||||
if not isinstance(destfile, Node.Node):
|
||||
destfile = self.path.find_or_declare(destfile)
|
||||
if not destfile:
|
||||
self.bld.fatal('invalid destfile %r for %r' % (destfile, self))
|
||||
tsk.set_outputs(destfile)
|
||||
tsk.basedir = basedir
|
||||
|
||||
jaropts.append('-C')
|
||||
jaropts.append(basedir.bldpath())
|
||||
jaropts.append('.')
|
||||
|
||||
tsk.env['JAROPTS'] = jaropts
|
||||
tsk.env['JARCREATE'] = jarcreate
|
||||
|
||||
if getattr(self, 'javac_task', None):
|
||||
tsk.set_run_after(self.javac_task)
|
||||
|
||||
@feature('jar')
|
||||
@after_method('jar_files')
|
||||
def use_jar_files(self):
|
||||
"""
|
||||
Process the *use* attribute to set the build order on the
|
||||
tasks created by another task generator.
|
||||
"""
|
||||
lst = []
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
names = self.to_list(getattr(self, 'use', []))
|
||||
get = self.bld.get_tgen_by_name
|
||||
for x in names:
|
||||
try:
|
||||
y = get(x)
|
||||
except Exception:
|
||||
self.uselib.append(x)
|
||||
else:
|
||||
y.post()
|
||||
self.jar_task.run_after.update(y.tasks)
|
||||
|
||||
class jar_create(Task.Task):
|
||||
"""
|
||||
Create a jar file
|
||||
"""
|
||||
color = 'GREEN'
|
||||
run_str = '${JAR} ${JARCREATE} ${TGT} ${JAROPTS}'
|
||||
|
||||
def runnable_status(self):
|
||||
"""
|
||||
Wait for dependent tasks to be executed, then read the
|
||||
files to update the list of inputs.
|
||||
"""
|
||||
for t in self.run_after:
|
||||
if not t.hasrun:
|
||||
return Task.ASK_LATER
|
||||
if not self.inputs:
|
||||
global JAR_RE
|
||||
try:
|
||||
self.inputs = [x for x in self.basedir.ant_glob(JAR_RE, remove=False) if id(x) != id(self.outputs[0])]
|
||||
except Exception:
|
||||
raise Errors.WafError('Could not find the basedir %r for %r' % (self.basedir, self))
|
||||
return super(jar_create, self).runnable_status()
|
||||
|
||||
class javac(Task.Task):
|
||||
"""
|
||||
Compile java files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
|
||||
nocache = True
|
||||
"""
|
||||
The .class files cannot be put into a cache at the moment
|
||||
"""
|
||||
|
||||
vars = ['CLASSPATH', 'JAVACFLAGS', 'JAVAC', 'OUTDIR']
|
||||
"""
|
||||
The javac task will be executed again if the variables CLASSPATH, JAVACFLAGS, JAVAC or OUTDIR change.
|
||||
"""
|
||||
|
||||
def runnable_status(self):
|
||||
"""
|
||||
Wait for dependent tasks to be complete, then read the file system to find the input nodes.
|
||||
"""
|
||||
for t in self.run_after:
|
||||
if not t.hasrun:
|
||||
return Task.ASK_LATER
|
||||
|
||||
if not self.inputs:
|
||||
global SOURCE_RE
|
||||
self.inputs = []
|
||||
for x in self.srcdir:
|
||||
self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False))
|
||||
return super(javac, self).runnable_status()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Execute the javac compiler
|
||||
"""
|
||||
env = self.env
|
||||
gen = self.generator
|
||||
bld = gen.bld
|
||||
wd = bld.bldnode.abspath()
|
||||
def to_list(xx):
|
||||
if isinstance(xx, str): return [xx]
|
||||
return xx
|
||||
cmd = []
|
||||
cmd.extend(to_list(env['JAVAC']))
|
||||
cmd.extend(['-classpath'])
|
||||
cmd.extend(to_list(env['CLASSPATH']))
|
||||
cmd.extend(['-d'])
|
||||
cmd.extend(to_list(env['OUTDIR']))
|
||||
cmd.extend(to_list(env['JAVACFLAGS']))
|
||||
|
||||
files = [a.path_from(bld.bldnode) for a in self.inputs]
|
||||
|
||||
# workaround for command line length limit:
|
||||
# http://support.microsoft.com/kb/830473
|
||||
tmp = None
|
||||
try:
|
||||
if len(str(files)) + len(str(cmd)) > 8192:
|
||||
(fd, tmp) = tempfile.mkstemp(dir=bld.bldnode.abspath())
|
||||
try:
|
||||
os.write(fd, '\n'.join(files).encode())
|
||||
finally:
|
||||
if tmp:
|
||||
os.close(fd)
|
||||
if Logs.verbose:
|
||||
Logs.debug('runner: %r' % (cmd + files))
|
||||
cmd.append('@' + tmp)
|
||||
else:
|
||||
cmd += files
|
||||
|
||||
ret = self.exec_command(cmd, cwd=wd, env=env.env or None)
|
||||
finally:
|
||||
if tmp:
|
||||
os.remove(tmp)
|
||||
return ret
|
||||
|
||||
def post_run(self):
|
||||
"""
|
||||
"""
|
||||
for n in self.generator.outdir.ant_glob('**/*.class'):
|
||||
n.sig = Utils.h_file(n.abspath()) # careful with this
|
||||
self.generator.bld.task_sigs[self.uid()] = self.cache_sig
|
||||
|
||||
@feature('javadoc')
|
||||
@after_method('process_rule')
|
||||
def create_javadoc(self):
|
||||
tsk = self.create_task('javadoc')
|
||||
tsk.classpath = getattr(self, 'classpath', [])
|
||||
self.javadoc_package = Utils.to_list(self.javadoc_package)
|
||||
if not isinstance(self.javadoc_output, Node.Node):
|
||||
self.javadoc_output = self.bld.path.find_or_declare(self.javadoc_output)
|
||||
|
||||
class javadoc(Task.Task):
|
||||
color = 'BLUE'
|
||||
|
||||
def __str__(self):
|
||||
return '%s: %s -> %s\n' % (self.__class__.__name__, self.generator.srcdir, self.generator.javadoc_output)
|
||||
|
||||
def run(self):
|
||||
env = self.env
|
||||
bld = self.generator.bld
|
||||
wd = bld.bldnode.abspath()
|
||||
|
||||
#add src node + bld node (for generated java code)
|
||||
srcpath = self.generator.path.abspath() + os.sep + self.generator.srcdir
|
||||
srcpath += os.pathsep
|
||||
srcpath += self.generator.path.get_bld().abspath() + os.sep + self.generator.srcdir
|
||||
|
||||
classpath = env.CLASSPATH
|
||||
classpath += os.pathsep
|
||||
classpath += os.pathsep.join(self.classpath)
|
||||
classpath = "".join(classpath)
|
||||
|
||||
self.last_cmd = lst = []
|
||||
lst.extend(Utils.to_list(env['JAVADOC']))
|
||||
lst.extend(['-d', self.generator.javadoc_output.abspath()])
|
||||
lst.extend(['-sourcepath', srcpath])
|
||||
lst.extend(['-classpath', classpath])
|
||||
lst.extend(['-subpackages'])
|
||||
lst.extend(self.generator.javadoc_package)
|
||||
lst = [x for x in lst if x]
|
||||
|
||||
self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0)
|
||||
|
||||
def post_run(self):
|
||||
nodes = self.generator.javadoc_output.ant_glob('**')
|
||||
for x in nodes:
|
||||
x.sig = Utils.h_file(x.abspath())
|
||||
self.generator.bld.task_sigs[self.uid()] = self.cache_sig
|
||||
|
||||
def configure(self):
|
||||
"""
|
||||
Detect the javac, java and jar programs
|
||||
"""
|
||||
# If JAVA_PATH is set, we prepend it to the path list
|
||||
java_path = self.environ['PATH'].split(os.pathsep)
|
||||
v = self.env
|
||||
|
||||
if 'JAVA_HOME' in self.environ:
|
||||
java_path = [os.path.join(self.environ['JAVA_HOME'], 'bin')] + java_path
|
||||
self.env['JAVA_HOME'] = [self.environ['JAVA_HOME']]
|
||||
|
||||
for x in 'javac java jar javadoc'.split():
|
||||
self.find_program(x, var=x.upper(), path_list=java_path)
|
||||
self.env[x.upper()] = self.cmd_to_list(self.env[x.upper()])
|
||||
|
||||
if 'CLASSPATH' in self.environ:
|
||||
v['CLASSPATH'] = self.environ['CLASSPATH']
|
||||
|
||||
if not v['JAR']: self.fatal('jar is required for making java packages')
|
||||
if not v['JAVAC']: self.fatal('javac is required for compiling java classes')
|
||||
|
||||
v['JARCREATE'] = 'cf' # can use cvf
|
||||
v['JAVACFLAGS'] = []
|
||||
|
||||
@conf
|
||||
def check_java_class(self, classname, with_classpath=None):
|
||||
"""
|
||||
Check if the specified java class exists
|
||||
|
||||
:param classname: class to check, like java.util.HashMap
|
||||
:type classname: string
|
||||
:param with_classpath: additional classpath to give
|
||||
:type with_classpath: string
|
||||
"""
|
||||
|
||||
javatestdir = '.waf-javatest'
|
||||
|
||||
classpath = javatestdir
|
||||
if self.env['CLASSPATH']:
|
||||
classpath += os.pathsep + self.env['CLASSPATH']
|
||||
if isinstance(with_classpath, str):
|
||||
classpath += os.pathsep + with_classpath
|
||||
|
||||
shutil.rmtree(javatestdir, True)
|
||||
os.mkdir(javatestdir)
|
||||
|
||||
Utils.writef(os.path.join(javatestdir, 'Test.java'), class_check_source)
|
||||
|
||||
# Compile the source
|
||||
self.exec_command(self.env['JAVAC'] + [os.path.join(javatestdir, 'Test.java')], shell=False)
|
||||
|
||||
# Try to run the app
|
||||
cmd = self.env['JAVA'] + ['-cp', classpath, 'Test', classname]
|
||||
self.to_log("%s\n" % str(cmd))
|
||||
found = self.exec_command(cmd, shell=False)
|
||||
|
||||
self.msg('Checking for java class %s' % classname, not found)
|
||||
|
||||
shutil.rmtree(javatestdir, True)
|
||||
|
||||
return found
|
||||
|
||||
@conf
|
||||
def check_jni_headers(conf):
|
||||
"""
|
||||
Check for jni headers and libraries. On success the conf.env variables xxx_JAVA are added for use in C/C++ targets::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c')
|
||||
|
||||
def configure(conf):
|
||||
conf.load('compiler_c java')
|
||||
conf.check_jni_headers()
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(source='a.c', target='app', use='JAVA')
|
||||
"""
|
||||
|
||||
if not conf.env.CC_NAME and not conf.env.CXX_NAME:
|
||||
conf.fatal('load a compiler first (gcc, g++, ..)')
|
||||
|
||||
if not conf.env.JAVA_HOME:
|
||||
conf.fatal('set JAVA_HOME in the system environment')
|
||||
|
||||
# jni requires the jvm
|
||||
javaHome = conf.env['JAVA_HOME'][0]
|
||||
|
||||
dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/include')
|
||||
if dir is None:
|
||||
dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/../Headers') # think different?!
|
||||
if dir is None:
|
||||
conf.fatal('JAVA_HOME does not seem to be set properly')
|
||||
|
||||
f = dir.ant_glob('**/(jni|jni_md).h')
|
||||
incDirs = [x.parent.abspath() for x in f]
|
||||
|
||||
dir = conf.root.find_dir(conf.env.JAVA_HOME[0])
|
||||
f = dir.ant_glob('**/*jvm.(so|dll|dylib)')
|
||||
libDirs = [x.parent.abspath() for x in f] or [javaHome]
|
||||
|
||||
# On windows, we need both the .dll and .lib to link. On my JDK, they are
|
||||
# in different directories...
|
||||
f = dir.ant_glob('**/*jvm.(lib)')
|
||||
if f:
|
||||
libDirs = [[x, y.parent.abspath()] for x in libDirs for y in f]
|
||||
|
||||
for d in libDirs:
|
||||
try:
|
||||
conf.check(header_name='jni.h', define_name='HAVE_JNI_H', lib='jvm',
|
||||
libpath=d, includes=incDirs, uselib_store='JAVA', uselib='JAVA')
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
else:
|
||||
conf.fatal('could not find lib jvm in %r (see config.log)' % libDirs)
|
||||
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
Support for the KDE4 libraries and msgfmt
|
||||
"""
|
||||
|
||||
import os, sys, re
|
||||
from waflib import Options, TaskGen, Task, Utils
|
||||
from waflib.TaskGen import feature, after_method
|
||||
|
||||
@feature('msgfmt')
|
||||
def apply_msgfmt(self):
|
||||
"""
|
||||
Process all languages to create .mo files and to install them::
|
||||
|
||||
def build(bld):
|
||||
bld(features='msgfmt', langs='es de fr', appname='myapp', install_path='${KDE4_LOCALE_INSTALL_DIR}')
|
||||
"""
|
||||
for lang in self.to_list(self.langs):
|
||||
node = self.path.find_resource(lang+'.po')
|
||||
task = self.create_task('msgfmt', node, node.change_ext('.mo'))
|
||||
|
||||
langname = lang.split('/')
|
||||
langname = langname[-1]
|
||||
|
||||
inst = getattr(self, 'install_path', '${KDE4_LOCALE_INSTALL_DIR}')
|
||||
|
||||
self.bld.install_as(
|
||||
inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + getattr(self, 'appname', 'set_your_appname') + '.mo',
|
||||
task.outputs[0],
|
||||
chmod = getattr(self, 'chmod', Utils.O644))
|
||||
|
||||
class msgfmt(Task.Task):
|
||||
"""
|
||||
Transform .po files into .mo files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${MSGFMT} ${SRC} -o ${TGT}'
|
||||
|
||||
def configure(self):
|
||||
"""
|
||||
Detect kde4-config and set various variables for the *use* system::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx kde4')
|
||||
def configure(conf):
|
||||
conf.load('compiler_cxx kde4')
|
||||
def build(bld):
|
||||
bld.program(source='main.c', target='app', use='KDECORE KIO KHTML')
|
||||
"""
|
||||
kdeconfig = self.find_program('kde4-config')
|
||||
prefix = self.cmd_and_log('%s --prefix' % kdeconfig).strip()
|
||||
fname = '%s/share/apps/cmake/modules/KDELibsDependencies.cmake' % prefix
|
||||
try: os.stat(fname)
|
||||
except OSError:
|
||||
fname = '%s/share/kde4/apps/cmake/modules/KDELibsDependencies.cmake' % prefix
|
||||
try: os.stat(fname)
|
||||
except OSError: self.fatal('could not open %s' % fname)
|
||||
|
||||
try:
|
||||
txt = Utils.readf(fname)
|
||||
except (OSError, IOError):
|
||||
self.fatal('could not read %s' % fname)
|
||||
|
||||
txt = txt.replace('\\\n', '\n')
|
||||
fu = re.compile('#(.*)\n')
|
||||
txt = fu.sub('', txt)
|
||||
|
||||
setregexp = re.compile('([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)')
|
||||
found = setregexp.findall(txt)
|
||||
|
||||
for (_, key, val) in found:
|
||||
#print key, val
|
||||
self.env[key] = val
|
||||
|
||||
# well well, i could just write an interpreter for cmake files
|
||||
self.env['LIB_KDECORE']= ['kdecore']
|
||||
self.env['LIB_KDEUI'] = ['kdeui']
|
||||
self.env['LIB_KIO'] = ['kio']
|
||||
self.env['LIB_KHTML'] = ['khtml']
|
||||
self.env['LIB_KPARTS'] = ['kparts']
|
||||
|
||||
self.env['LIBPATH_KDECORE'] = [os.path.join(self.env.KDE4_LIB_INSTALL_DIR, 'kde4', 'devel'), self.env.KDE4_LIB_INSTALL_DIR]
|
||||
self.env['INCLUDES_KDECORE'] = [self.env['KDE4_INCLUDE_INSTALL_DIR']]
|
||||
self.env.append_value('INCLUDES_KDECORE', [self.env['KDE4_INCLUDE_INSTALL_DIR']+ os.sep + 'KDE'])
|
||||
|
||||
self.find_program('msgfmt', var='MSGFMT')
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Alex Rønne Petersen, 2012 (alexrp/Zor)
|
||||
|
||||
import sys
|
||||
from waflib.Tools import ar, d
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_ldc2(conf):
|
||||
"""
|
||||
Find the program *ldc2* and set the variable *D*
|
||||
"""
|
||||
|
||||
conf.find_program(['ldc2'], var='D')
|
||||
|
||||
out = conf.cmd_and_log([conf.env.D, '-version'])
|
||||
if out.find("based on DMD v2.") == -1:
|
||||
conf.fatal("detected compiler is not ldc2")
|
||||
|
||||
@conf
|
||||
def common_flags_ldc2(conf):
|
||||
"""
|
||||
Set the D flags required by *ldc2*
|
||||
"""
|
||||
|
||||
v = conf.env
|
||||
|
||||
v['D_SRC_F'] = ['-c']
|
||||
v['D_TGT_F'] = '-of%s'
|
||||
|
||||
v['D_LINKER'] = v['D']
|
||||
v['DLNK_SRC_F'] = ''
|
||||
v['DLNK_TGT_F'] = '-of%s'
|
||||
v['DINC_ST'] = '-I%s'
|
||||
|
||||
v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''
|
||||
v['DSTLIB_ST'] = v['DSHLIB_ST'] = '-L-l%s'
|
||||
v['DSTLIBPATH_ST'] = v['DLIBPATH_ST'] = '-L-L%s'
|
||||
|
||||
v['LINKFLAGS_dshlib'] = ['-L-shared']
|
||||
|
||||
v['DHEADER_ext'] = '.di'
|
||||
v['DFLAGS_d_with_header'] = ['-H', '-Hf']
|
||||
v['D_HDR_F'] = '%s'
|
||||
|
||||
v['LINKFLAGS'] = []
|
||||
v['DFLAGS_dshlib'] = ['-relocation-model=pic']
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Configuration for *ldc2*
|
||||
"""
|
||||
|
||||
conf.find_ldc2()
|
||||
conf.load('ar')
|
||||
conf.load('d')
|
||||
conf.common_flags_ldc2()
|
||||
conf.d_platform_flags()
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Sebastian Schlingmann, 2008
|
||||
# Thomas Nagy, 2008-2010 (ita)
|
||||
|
||||
"""
|
||||
Lua support.
|
||||
|
||||
Compile *.lua* files into *.luac*::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('lua')
|
||||
conf.env.LUADIR = '/usr/local/share/myapp/scripts/'
|
||||
def build(bld):
|
||||
bld(source='foo.lua')
|
||||
"""
|
||||
|
||||
from waflib.TaskGen import extension
|
||||
from waflib import Task, Utils
|
||||
|
||||
@extension('.lua')
|
||||
def add_lua(self, node):
|
||||
tsk = self.create_task('luac', node, node.change_ext('.luac'))
|
||||
inst_to = getattr(self, 'install_path', self.env.LUADIR and '${LUADIR}' or None)
|
||||
if inst_to:
|
||||
self.bld.install_files(inst_to, tsk.outputs)
|
||||
return tsk
|
||||
|
||||
class luac(Task.Task):
|
||||
run_str = '${LUAC} -s -o ${TGT} ${SRC}'
|
||||
color = 'PINK'
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the luac compiler and set *conf.env.LUAC*
|
||||
"""
|
||||
conf.find_program('luac', var='LUAC')
|
||||
|
||||
+1060
File diff suppressed because it is too large
Load Diff
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2008-2010 (ita)
|
||||
|
||||
"""
|
||||
Nasm tool (asm processing)
|
||||
"""
|
||||
|
||||
import waflib.Tools.asm # leave this
|
||||
from waflib.TaskGen import feature
|
||||
|
||||
@feature('asm')
|
||||
def apply_nasm_vars(self):
|
||||
"""provided for compatibility"""
|
||||
self.env.append_value('ASFLAGS', self.to_list(getattr(self, 'nasm_flags', [])))
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect nasm/yasm and set the variable *AS*
|
||||
"""
|
||||
nasm = conf.find_program(['nasm', 'yasm'], var='AS')
|
||||
conf.env.AS_TGT_F = ['-o']
|
||||
conf.env.ASLNK_TGT_F = ['-o']
|
||||
conf.load('asm')
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# andersg at 0x63.nu 2007
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
"""
|
||||
Support for Perl extensions. A C/C++ compiler is required::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c perl')
|
||||
def configure(conf):
|
||||
conf.load('compiler_c perl')
|
||||
conf.check_perl_version((5,6,0))
|
||||
conf.check_perl_ext_devel()
|
||||
conf.check_perl_module('Cairo')
|
||||
conf.check_perl_module('Devel::PPPort 4.89')
|
||||
def build(bld):
|
||||
bld(
|
||||
features = 'c cshlib perlext',
|
||||
source = 'Mytest.xs',
|
||||
target = 'Mytest',
|
||||
install_path = '${ARCHDIR_PERL}/auto')
|
||||
bld.install_files('${ARCHDIR_PERL}', 'Mytest.pm')
|
||||
"""
|
||||
|
||||
import os
|
||||
from waflib import Task, Options, Utils
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import extension, feature, before_method
|
||||
|
||||
@before_method('apply_incpaths', 'apply_link', 'propagate_uselib_vars')
|
||||
@feature('perlext')
|
||||
def init_perlext(self):
|
||||
"""
|
||||
Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the
|
||||
*lib* prefix from library names.
|
||||
"""
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
if not 'PERLEXT' in self.uselib: self.uselib.append('PERLEXT')
|
||||
self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['perlext_PATTERN']
|
||||
|
||||
@extension('.xs')
|
||||
def xsubpp_file(self, node):
|
||||
"""
|
||||
Create :py:class:`waflib.Tools.perl.xsubpp` tasks to process *.xs* files
|
||||
"""
|
||||
outnode = node.change_ext('.c')
|
||||
self.create_task('xsubpp', node, outnode)
|
||||
self.source.append(outnode)
|
||||
|
||||
class xsubpp(Task.Task):
|
||||
"""
|
||||
Process *.xs* files
|
||||
"""
|
||||
run_str = '${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}'
|
||||
color = 'BLUE'
|
||||
ext_out = ['.h']
|
||||
|
||||
@conf
|
||||
def check_perl_version(self, minver=None):
|
||||
"""
|
||||
Check if Perl is installed, and set the variable PERL.
|
||||
minver is supposed to be a tuple
|
||||
"""
|
||||
res = True
|
||||
|
||||
if minver:
|
||||
cver = '.'.join(map(str,minver))
|
||||
else:
|
||||
cver = ''
|
||||
|
||||
self.start_msg('Checking for minimum perl version %s' % cver)
|
||||
|
||||
perl = getattr(Options.options, 'perlbinary', None)
|
||||
|
||||
if not perl:
|
||||
perl = self.find_program('perl', var='PERL')
|
||||
|
||||
if not perl:
|
||||
self.end_msg("Perl not found", color="YELLOW")
|
||||
return False
|
||||
|
||||
self.env['PERL'] = perl
|
||||
|
||||
version = self.cmd_and_log([perl, "-e", 'printf \"%vd\", $^V'])
|
||||
if not version:
|
||||
res = False
|
||||
version = "Unknown"
|
||||
elif not minver is None:
|
||||
ver = tuple(map(int, version.split(".")))
|
||||
if ver < minver:
|
||||
res = False
|
||||
|
||||
self.end_msg(version, color=res and "GREEN" or "YELLOW")
|
||||
return res
|
||||
|
||||
@conf
|
||||
def check_perl_module(self, module):
|
||||
"""
|
||||
Check if specified perlmodule is installed.
|
||||
|
||||
The minimum version can be specified by specifying it after modulename
|
||||
like this::
|
||||
|
||||
def configure(conf):
|
||||
conf.check_perl_module("Some::Module 2.92")
|
||||
"""
|
||||
cmd = [self.env['PERL'], '-e', 'use %s' % module]
|
||||
self.start_msg('perl module %s' % module)
|
||||
try:
|
||||
r = self.cmd_and_log(cmd)
|
||||
except Exception:
|
||||
self.end_msg(False)
|
||||
return None
|
||||
self.end_msg(r or True)
|
||||
return r
|
||||
|
||||
@conf
|
||||
def check_perl_ext_devel(self):
|
||||
"""
|
||||
Check for configuration needed to build perl extensions.
|
||||
|
||||
Sets different xxx_PERLEXT variables in the environment.
|
||||
|
||||
Also sets the ARCHDIR_PERL variable useful as installation path,
|
||||
which can be overridden by ``--with-perl-archdir`` option.
|
||||
"""
|
||||
|
||||
env = self.env
|
||||
perl = env.PERL
|
||||
if not perl:
|
||||
self.fatal('find perl first')
|
||||
|
||||
def read_out(cmd):
|
||||
return Utils.to_list(self.cmd_and_log(perl + cmd))
|
||||
|
||||
env['LINKFLAGS_PERLEXT'] = read_out(" -MConfig -e'print $Config{lddlflags}'")
|
||||
env['INCLUDES_PERLEXT'] = read_out(" -MConfig -e'print \"$Config{archlib}/CORE\"'")
|
||||
env['CFLAGS_PERLEXT'] = read_out(" -MConfig -e'print \"$Config{ccflags} $Config{cccdlflags}\"'")
|
||||
|
||||
env['XSUBPP'] = read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/xsubpp$Config{exe_ext}\"'")
|
||||
env['EXTUTILS_TYPEMAP'] = read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/typemap\"'")
|
||||
|
||||
if not getattr(Options.options, 'perlarchdir', None):
|
||||
env['ARCHDIR_PERL'] = self.cmd_and_log(perl + " -MConfig -e'print $Config{sitearch}'")
|
||||
else:
|
||||
env['ARCHDIR_PERL'] = getattr(Options.options, 'perlarchdir')
|
||||
|
||||
env['perlext_PATTERN'] = '%s.' + self.cmd_and_log(perl + " -MConfig -e'print $Config{dlext}'")
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add the ``--with-perl-archdir`` and ``--with-perl-binary`` command-line options.
|
||||
"""
|
||||
opt.add_option('--with-perl-binary', type='string', dest='perlbinary', help = 'Specify alternate perl binary', default=None)
|
||||
opt.add_option('--with-perl-archdir', type='string', dest='perlarchdir', help = 'Specify directory where to install arch specific files', default=None)
|
||||
|
||||
+540
@@ -0,0 +1,540 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2007-2010 (ita)
|
||||
# Gustavo Carneiro (gjc), 2007
|
||||
|
||||
"""
|
||||
Support for Python, detect the headers and libraries and provide
|
||||
*use* variables to link C/C++ programs against them::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c python')
|
||||
def configure(conf):
|
||||
conf.load('compiler_c python')
|
||||
conf.check_python_version((2,4,2))
|
||||
conf.check_python_headers()
|
||||
def build(bld):
|
||||
bld.program(features='pyembed', source='a.c', target='myprog')
|
||||
bld.shlib(features='pyext', source='b.c', target='mylib')
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib import Utils, Options, Errors, Logs
|
||||
from waflib.TaskGen import extension, before_method, after_method, feature
|
||||
from waflib.Configure import conf
|
||||
|
||||
FRAG = '''
|
||||
#include <Python.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void Py_Initialize(void);
|
||||
void Py_Finalize(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
Py_Initialize();
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
"""
|
||||
Piece of C/C++ code used in :py:func:`waflib.Tools.python.check_python_headers`
|
||||
"""
|
||||
|
||||
INST = '''
|
||||
import sys, py_compile
|
||||
py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||
'''
|
||||
"""
|
||||
Piece of Python code used in :py:func:`waflib.Tools.python.install_pyfile` for installing python files
|
||||
"""
|
||||
|
||||
DISTUTILS_IMP = ['from distutils.sysconfig import get_config_var, get_python_lib']
|
||||
|
||||
@extension('.py')
|
||||
def process_py(self, node):
|
||||
"""
|
||||
Add a callback using :py:func:`waflib.Tools.python.install_pyfile` to install a python file
|
||||
"""
|
||||
try:
|
||||
if not self.bld.is_install:
|
||||
return
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
try:
|
||||
if not self.install_path:
|
||||
return
|
||||
except AttributeError:
|
||||
self.install_path = '${PYTHONDIR}'
|
||||
|
||||
# i wonder now why we wanted to do this after the build is over
|
||||
# issue #901: people want to preserve the structure of installed files
|
||||
def inst_py(ctx):
|
||||
install_from = getattr(self, 'install_from', None)
|
||||
if install_from:
|
||||
install_from = self.path.find_dir(install_from)
|
||||
install_pyfile(self, node, install_from)
|
||||
self.bld.add_post_fun(inst_py)
|
||||
|
||||
def install_pyfile(self, node, install_from=None):
|
||||
"""
|
||||
Execute the installation of a python file
|
||||
|
||||
:param node: python file
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
|
||||
from_node = install_from or node.parent
|
||||
tsk = self.bld.install_as(self.install_path + '/' + node.path_from(from_node), node, postpone=False)
|
||||
path = tsk.get_install_path()
|
||||
|
||||
if self.bld.is_install < 0:
|
||||
Logs.info("+ removing byte compiled python files")
|
||||
for x in 'co':
|
||||
try:
|
||||
os.remove(path + x)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if self.bld.is_install > 0:
|
||||
try:
|
||||
st1 = os.stat(path)
|
||||
except OSError:
|
||||
Logs.error('The python file is missing, this should not happen')
|
||||
|
||||
for x in ['c', 'o']:
|
||||
do_inst = self.env['PY' + x.upper()]
|
||||
try:
|
||||
st2 = os.stat(path + x)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
if st1.st_mtime <= st2.st_mtime:
|
||||
do_inst = False
|
||||
|
||||
if do_inst:
|
||||
lst = (x == 'o') and [self.env['PYFLAGS_OPT']] or []
|
||||
(a, b, c) = (path, path + x, tsk.get_install_path(destdir=False) + x)
|
||||
argv = self.env['PYTHON'] + lst + ['-c', INST, a, b, c]
|
||||
Logs.info('+ byte compiling %r' % (path + x))
|
||||
env = self.env.env or None
|
||||
ret = Utils.subprocess.Popen(argv, env=env).wait()
|
||||
if ret:
|
||||
raise Errors.WafError('py%s compilation failed %r' % (x, path))
|
||||
|
||||
@feature('py')
|
||||
def feature_py(self):
|
||||
"""
|
||||
Dummy feature which does nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
@feature('pyext')
|
||||
@before_method('propagate_uselib_vars', 'apply_link')
|
||||
@after_method('apply_bundle')
|
||||
def init_pyext(self):
|
||||
"""
|
||||
Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the
|
||||
*lib* prefix from library names.
|
||||
"""
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
if not 'PYEXT' in self.uselib:
|
||||
self.uselib.append('PYEXT')
|
||||
# override shlib_PATTERN set by the osx module
|
||||
self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.macbundle_PATTERN = self.env.pyext_PATTERN
|
||||
self.env.fcshlib_PATTERN = self.env.dshlib_PATTERN = self.env.pyext_PATTERN
|
||||
|
||||
try:
|
||||
if not self.install_path:
|
||||
return
|
||||
except AttributeError:
|
||||
self.install_path = '${PYTHONARCHDIR}'
|
||||
|
||||
@feature('pyext')
|
||||
@before_method('apply_link', 'apply_bundle')
|
||||
def set_bundle(self):
|
||||
if Utils.unversioned_sys_platform() == 'darwin':
|
||||
self.mac_bundle = True
|
||||
|
||||
@before_method('propagate_uselib_vars')
|
||||
@feature('pyembed')
|
||||
def init_pyembed(self):
|
||||
"""
|
||||
Add the PYEMBED variable.
|
||||
"""
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
if not 'PYEMBED' in self.uselib:
|
||||
self.uselib.append('PYEMBED')
|
||||
|
||||
@conf
|
||||
def get_python_variables(self, variables, imports=None):
|
||||
"""
|
||||
Spawn a new python process to dump configuration variables
|
||||
|
||||
:param variables: variables to print
|
||||
:type variables: list of string
|
||||
:param imports: one import by element
|
||||
:type imports: list of string
|
||||
:return: the variable values
|
||||
:rtype: list of string
|
||||
"""
|
||||
if not imports:
|
||||
try:
|
||||
imports = self.python_imports
|
||||
except AttributeError:
|
||||
imports = DISTUTILS_IMP
|
||||
|
||||
program = list(imports) # copy
|
||||
program.append('')
|
||||
for v in variables:
|
||||
program.append("print(repr(%s))" % v)
|
||||
os_env = dict(os.environ)
|
||||
try:
|
||||
del os_env['MACOSX_DEPLOYMENT_TARGET'] # see comments in the OSX tool
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
out = self.cmd_and_log(self.env.PYTHON + ['-c', '\n'.join(program)], env=os_env)
|
||||
except Errors.WafError:
|
||||
self.fatal('The distutils module is unusable: install "python-devel"?')
|
||||
self.to_log(out)
|
||||
return_values = []
|
||||
for s in out.split('\n'):
|
||||
s = s.strip()
|
||||
if not s:
|
||||
continue
|
||||
if s == 'None':
|
||||
return_values.append(None)
|
||||
elif (s[0] == "'" and s[-1] == "'") or (s[0] == '"' and s[-1] == '"'):
|
||||
return_values.append(eval(s))
|
||||
elif s[0].isdigit():
|
||||
return_values.append(int(s))
|
||||
else: break
|
||||
return return_values
|
||||
|
||||
@conf
|
||||
def check_python_headers(conf):
|
||||
"""
|
||||
Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
|
||||
On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:
|
||||
|
||||
* PYEXT: for compiling python extensions
|
||||
* PYEMBED: for embedding a python interpreter
|
||||
"""
|
||||
|
||||
# FIXME rewrite
|
||||
|
||||
env = conf.env
|
||||
if not env['CC_NAME'] and not env['CXX_NAME']:
|
||||
conf.fatal('load a compiler first (gcc, g++, ..)')
|
||||
|
||||
if not env['PYTHON_VERSION']:
|
||||
conf.check_python_version()
|
||||
|
||||
pybin = conf.env.PYTHON
|
||||
if not pybin:
|
||||
conf.fatal('Could not find the python executable')
|
||||
|
||||
v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split()
|
||||
try:
|
||||
lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v])
|
||||
except RuntimeError:
|
||||
conf.fatal("Python development headers not found (-v for details).")
|
||||
|
||||
vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
|
||||
conf.to_log("Configuration returned from %r:\n%r\n" % (pybin, '\n'.join(vals)))
|
||||
|
||||
dct = dict(zip(v, lst))
|
||||
x = 'MACOSX_DEPLOYMENT_TARGET'
|
||||
if dct[x]:
|
||||
conf.env[x] = conf.environ[x] = dct[x]
|
||||
|
||||
env['pyext_PATTERN'] = '%s' + dct['SO'] # not a mistake
|
||||
|
||||
# Check for python libraries for embedding
|
||||
|
||||
all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
|
||||
conf.parse_flags(all_flags, 'PYEMBED')
|
||||
|
||||
all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
|
||||
conf.parse_flags(all_flags, 'PYEXT')
|
||||
|
||||
result = None
|
||||
#name = 'python' + env['PYTHON_VERSION']
|
||||
|
||||
# TODO simplify this
|
||||
for name in ('python' + env['PYTHON_VERSION'], 'python' + env['PYTHON_VERSION'] + 'm', 'python' + env['PYTHON_VERSION'].replace('.', '')):
|
||||
|
||||
# LIBPATH_PYEMBED is already set; see if it works.
|
||||
if not result and env['LIBPATH_PYEMBED']:
|
||||
path = env['LIBPATH_PYEMBED']
|
||||
conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
|
||||
result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name)
|
||||
|
||||
if not result and dct['LIBDIR']:
|
||||
path = [dct['LIBDIR']]
|
||||
conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
|
||||
result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name)
|
||||
|
||||
if not result and dct['LIBPL']:
|
||||
path = [dct['LIBPL']]
|
||||
conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
|
||||
result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name)
|
||||
|
||||
if not result:
|
||||
path = [os.path.join(dct['prefix'], "libs")]
|
||||
conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
|
||||
result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name)
|
||||
|
||||
if result:
|
||||
break # do not forget to set LIBPATH_PYEMBED
|
||||
|
||||
if result:
|
||||
env['LIBPATH_PYEMBED'] = path
|
||||
env.append_value('LIB_PYEMBED', [name])
|
||||
else:
|
||||
conf.to_log("\n\n### LIB NOT FOUND\n")
|
||||
|
||||
# under certain conditions, python extensions must link to
|
||||
# python libraries, not just python embedding programs.
|
||||
if (Utils.is_win32 or sys.platform.startswith('os2')
|
||||
or dct['Py_ENABLE_SHARED']):
|
||||
env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED']
|
||||
env['LIB_PYEXT'] = env['LIB_PYEMBED']
|
||||
|
||||
# We check that pythonX.Y-config exists, and if it exists we
|
||||
# use it to get only the includes, else fall back to distutils.
|
||||
num = '.'.join(env['PYTHON_VERSION'].split('.')[:2])
|
||||
conf.find_program([''.join(pybin) + '-config', 'python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', mandatory=False)
|
||||
|
||||
includes = []
|
||||
if conf.env.PYTHON_CONFIG:
|
||||
for incstr in conf.cmd_and_log([ conf.env.PYTHON_CONFIG, '--includes']).strip().split():
|
||||
# strip the -I or /I
|
||||
if (incstr.startswith('-I') or incstr.startswith('/I')):
|
||||
incstr = incstr[2:]
|
||||
# append include path, unless already given
|
||||
if incstr not in includes:
|
||||
includes.append(incstr)
|
||||
conf.to_log("Include path for Python extensions (found via python-config --includes): %r\n" % (includes,))
|
||||
env['INCLUDES_PYEXT'] = includes
|
||||
env['INCLUDES_PYEMBED'] = includes
|
||||
else:
|
||||
conf.to_log("Include path for Python extensions "
|
||||
"(found via distutils module): %r\n" % (dct['INCLUDEPY'],))
|
||||
env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]
|
||||
env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]
|
||||
|
||||
# Code using the Python API needs to be compiled with -fno-strict-aliasing
|
||||
if env['CC_NAME'] == 'gcc':
|
||||
env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
|
||||
env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
|
||||
if env['CXX_NAME'] == 'gcc':
|
||||
env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
|
||||
env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])
|
||||
|
||||
if env.CC_NAME == "msvc":
|
||||
from distutils.msvccompiler import MSVCCompiler
|
||||
dist_compiler = MSVCCompiler()
|
||||
dist_compiler.initialize()
|
||||
env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
|
||||
env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
|
||||
env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)
|
||||
|
||||
# See if it compiles
|
||||
try:
|
||||
conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H',
|
||||
uselib='PYEMBED', fragment=FRAG,
|
||||
errmsg=':-(')
|
||||
except conf.errors.ConfigurationError:
|
||||
# python3.2, oh yeah
|
||||
xx = conf.env.CXX_NAME and 'cxx' or 'c'
|
||||
|
||||
flags = ['--cflags', '--libs', '--ldflags']
|
||||
|
||||
for f in flags:
|
||||
conf.check_cfg(msg='Asking python-config for pyembed %s flags' % f,
|
||||
path=conf.env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=[f])
|
||||
conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', msg='Getting pyembed flags from python-config',
|
||||
fragment=FRAG, errmsg='Could not build a python embedded interpreter',
|
||||
features='%s %sprogram pyembed' % (xx, xx))
|
||||
|
||||
for f in flags:
|
||||
conf.check_cfg(msg='Asking python-config for pyext %s flags' % f,
|
||||
path=conf.env.PYTHON_CONFIG, package='', uselib_store='PYEXT', args=[f])
|
||||
conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', msg='Getting pyext flags from python-config',
|
||||
features='%s %sshlib pyext' % (xx, xx), fragment=FRAG, errmsg='Could not build python extensions')
|
||||
|
||||
@conf
|
||||
def check_python_version(conf, minver=None):
|
||||
"""
|
||||
Check if the python interpreter is found matching a given minimum version.
|
||||
minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver.
|
||||
|
||||
If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR'
|
||||
(eg. '2.4') of the actual python version found, and PYTHONDIR is
|
||||
defined, pointing to the site-packages directory appropriate for
|
||||
this python version, where modules/packages/extensions should be
|
||||
installed.
|
||||
|
||||
:param minver: minimum version
|
||||
:type minver: tuple of int
|
||||
"""
|
||||
assert minver is None or isinstance(minver, tuple)
|
||||
pybin = conf.env['PYTHON']
|
||||
if not pybin:
|
||||
conf.fatal('could not find the python executable')
|
||||
|
||||
# Get python version string
|
||||
cmd = pybin + ['-c', 'import sys\nfor x in sys.version_info: print(str(x))']
|
||||
Logs.debug('python: Running python command %r' % cmd)
|
||||
lines = conf.cmd_and_log(cmd).split()
|
||||
assert len(lines) == 5, "found %i lines, expected 5: %r" % (len(lines), lines)
|
||||
pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4]))
|
||||
|
||||
# compare python version with the minimum required
|
||||
result = (minver is None) or (pyver_tuple >= minver)
|
||||
|
||||
if result:
|
||||
# define useful environment variables
|
||||
pyver = '.'.join([str(x) for x in pyver_tuple[:2]])
|
||||
conf.env['PYTHON_VERSION'] = pyver
|
||||
|
||||
if 'PYTHONDIR' in conf.environ:
|
||||
pydir = conf.environ['PYTHONDIR']
|
||||
else:
|
||||
if Utils.is_win32:
|
||||
(python_LIBDEST, pydir) = conf.get_python_variables(
|
||||
["get_config_var('LIBDEST') or ''",
|
||||
"get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']])
|
||||
else:
|
||||
python_LIBDEST = None
|
||||
(pydir,) = conf.get_python_variables( ["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']])
|
||||
if python_LIBDEST is None:
|
||||
if conf.env['LIBDIR']:
|
||||
python_LIBDEST = os.path.join(conf.env['LIBDIR'], "python" + pyver)
|
||||
else:
|
||||
python_LIBDEST = os.path.join(conf.env['PREFIX'], "lib", "python" + pyver)
|
||||
|
||||
|
||||
if 'PYTHONARCHDIR' in conf.environ:
|
||||
pyarchdir = conf.environ['PYTHONARCHDIR']
|
||||
else:
|
||||
(pyarchdir, ) = conf.get_python_variables( ["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']])
|
||||
if not pyarchdir:
|
||||
pyarchdir = pydir
|
||||
|
||||
if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist
|
||||
conf.define('PYTHONDIR', pydir)
|
||||
conf.define('PYTHONARCHDIR', pyarchdir)
|
||||
|
||||
conf.env['PYTHONDIR'] = pydir
|
||||
conf.env['PYTHONARCHDIR'] = pyarchdir
|
||||
|
||||
# Feedback
|
||||
pyver_full = '.'.join(map(str, pyver_tuple[:3]))
|
||||
if minver is None:
|
||||
conf.msg('Checking for python version', pyver_full)
|
||||
else:
|
||||
minver_str = '.'.join(map(str, minver))
|
||||
conf.msg('Checking for python version', pyver_tuple, ">= %s" % (minver_str,) and 'GREEN' or 'YELLOW')
|
||||
|
||||
if not result:
|
||||
conf.fatal('The python version is too old, expecting %r' % (minver,))
|
||||
|
||||
PYTHON_MODULE_TEMPLATE = '''
|
||||
import %s as current_module
|
||||
version = getattr(current_module, '__version__', None)
|
||||
if version is not None:
|
||||
print(str(version))
|
||||
else:
|
||||
print('unknown version')
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_python_module(conf, module_name, condition=''):
|
||||
"""
|
||||
Check if the selected python interpreter can import the given python module::
|
||||
|
||||
def configure(conf):
|
||||
conf.check_python_module('pygccxml')
|
||||
conf.check_python_module('re', condition="ver > num(2, 0, 4) and ver <= num(3, 0, 0)")
|
||||
|
||||
:param module_name: module
|
||||
:type module_name: string
|
||||
"""
|
||||
msg = 'Python module %s' % module_name
|
||||
if condition:
|
||||
msg = '%s (%s)' % (msg, condition)
|
||||
conf.start_msg(msg)
|
||||
try:
|
||||
ret = conf.cmd_and_log(conf.env['PYTHON'] + ['-c', PYTHON_MODULE_TEMPLATE % module_name])
|
||||
except Exception:
|
||||
conf.end_msg(False)
|
||||
conf.fatal('Could not find the python module %r' % module_name)
|
||||
|
||||
ret = ret.strip()
|
||||
if condition:
|
||||
conf.end_msg(ret)
|
||||
if ret == 'unknown version':
|
||||
conf.fatal('Could not check the %s version' % module_name)
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
def num(*k):
|
||||
if isinstance(k[0], int):
|
||||
return LooseVersion('.'.join([str(x) for x in k]))
|
||||
else:
|
||||
return LooseVersion(k[0])
|
||||
d = {'num': num, 'ver': LooseVersion(ret)}
|
||||
ev = eval(condition, {}, d)
|
||||
if not ev:
|
||||
conf.fatal('The %s version does not satisfy the requirements' % module_name)
|
||||
else:
|
||||
if ret == 'unknown version':
|
||||
conf.end_msg(True)
|
||||
else:
|
||||
conf.end_msg(ret)
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the python interpreter
|
||||
"""
|
||||
try:
|
||||
conf.find_program('python', var='PYTHON')
|
||||
except conf.errors.ConfigurationError:
|
||||
Logs.warn("could not find a python executable, setting to sys.executable '%s'" % sys.executable)
|
||||
conf.env.PYTHON = sys.executable
|
||||
|
||||
if conf.env.PYTHON != sys.executable:
|
||||
Logs.warn("python executable %r differs from system %r" % (conf.env.PYTHON, sys.executable))
|
||||
conf.env.PYTHON = conf.cmd_to_list(conf.env.PYTHON)
|
||||
|
||||
v = conf.env
|
||||
v['PYCMD'] = '"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"'
|
||||
v['PYFLAGS'] = ''
|
||||
v['PYFLAGS_OPT'] = '-O'
|
||||
|
||||
v['PYC'] = getattr(Options.options, 'pyc', 1)
|
||||
v['PYO'] = getattr(Options.options, 'pyo', 1)
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add the options ``--nopyc`` and ``--nopyo``
|
||||
"""
|
||||
opt.add_option('--nopyc',
|
||||
action='store_false',
|
||||
default=1,
|
||||
help = 'Do not install bytecode compiled .pyc files (configuration) [Default:install]',
|
||||
dest = 'pyc')
|
||||
opt.add_option('--nopyo',
|
||||
action='store_false',
|
||||
default=1,
|
||||
help='Do not install optimised compiled .pyo files (configuration) [Default:install]',
|
||||
dest='pyo')
|
||||
|
||||
+715
@@ -0,0 +1,715 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
|
||||
Tool Description
|
||||
================
|
||||
|
||||
This tool helps with finding Qt4 tools and libraries,
|
||||
and also provides syntactic sugar for using Qt4 tools.
|
||||
|
||||
The following snippet illustrates the tool usage::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx qt4')
|
||||
|
||||
def configure(conf):
|
||||
conf.load('compiler_cxx qt4')
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features = 'qt4 cxx cxxprogram',
|
||||
uselib = 'QTCORE QTGUI QTOPENGL QTSVG',
|
||||
source = 'main.cpp textures.qrc aboutDialog.ui',
|
||||
target = 'window',
|
||||
)
|
||||
|
||||
Here, the UI description and resource files will be processed
|
||||
to generate code.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Load the "qt4" tool.
|
||||
|
||||
You also need to edit your sources accordingly:
|
||||
|
||||
- the normal way of doing things is to have your C++ files
|
||||
include the .moc file.
|
||||
This is regarded as the best practice (and provides much faster
|
||||
compilations).
|
||||
It also implies that the include paths have beenset properly.
|
||||
|
||||
- to have the include paths added automatically, use the following::
|
||||
|
||||
from waflib.TaskGen import feature, before_method, after_method
|
||||
@feature('cxx')
|
||||
@after_method('process_source')
|
||||
@before_method('apply_incpaths')
|
||||
def add_includes_paths(self):
|
||||
incs = set(self.to_list(getattr(self, 'includes', '')))
|
||||
for x in self.compiled_tasks:
|
||||
incs.add(x.inputs[0].parent.path_from(self.path))
|
||||
self.includes = list(incs)
|
||||
|
||||
Note: another tool provides Qt processing that does not require
|
||||
.moc includes, see 'playground/slow_qt/'.
|
||||
|
||||
A few options (--qt{dir,bin,...}) and environment variables
|
||||
(QT4_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool,
|
||||
tool path selection, etc; please read the source for more info.
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
from xml.sax import make_parser
|
||||
from xml.sax.handler import ContentHandler
|
||||
except ImportError:
|
||||
has_xml = False
|
||||
ContentHandler = object
|
||||
else:
|
||||
has_xml = True
|
||||
|
||||
import os, sys
|
||||
from waflib.Tools import c_preproc, cxx
|
||||
from waflib import Task, Utils, Options, Errors
|
||||
from waflib.TaskGen import feature, after_method, extension
|
||||
from waflib.Configure import conf
|
||||
from waflib import Logs
|
||||
|
||||
MOC_H = ['.h', '.hpp', '.hxx', '.hh']
|
||||
"""
|
||||
File extensions associated to the .moc files
|
||||
"""
|
||||
|
||||
EXT_RCC = ['.qrc']
|
||||
"""
|
||||
File extension for the resource (.qrc) files
|
||||
"""
|
||||
|
||||
EXT_UI = ['.ui']
|
||||
"""
|
||||
File extension for the user interface (.ui) files
|
||||
"""
|
||||
|
||||
EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C']
|
||||
"""
|
||||
File extensions of C++ files that may require a .moc processing
|
||||
"""
|
||||
|
||||
QT4_LIBS = "QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtXmlPatterns QtWebKit Qt3Support QtHelp QtScript QtDeclarative QtDesigner"
|
||||
|
||||
class qxx(Task.classes['cxx']):
|
||||
"""
|
||||
Each C++ file can have zero or several .moc files to create.
|
||||
They are known only when the files are scanned (preprocessor)
|
||||
To avoid scanning the c++ files each time (parsing C/C++), the results
|
||||
are retrieved from the task cache (bld.node_deps/bld.raw_deps).
|
||||
The moc tasks are also created *dynamically* during the build.
|
||||
"""
|
||||
|
||||
def __init__(self, *k, **kw):
|
||||
Task.Task.__init__(self, *k, **kw)
|
||||
self.moc_done = 0
|
||||
|
||||
def scan(self):
|
||||
"""
|
||||
Re-use the C/C++ scanner, but remove the moc files from the dependencies
|
||||
since the .cpp file already depends on all the headers
|
||||
"""
|
||||
(nodes, names) = c_preproc.scan(self)
|
||||
lst = []
|
||||
for x in nodes:
|
||||
# short lists, no need to use sets
|
||||
if x.name.endswith('.moc'):
|
||||
s = x.path_from(self.inputs[0].parent.get_bld())
|
||||
if s not in names:
|
||||
names.append(s)
|
||||
else:
|
||||
lst.append(x)
|
||||
return (lst, names)
|
||||
|
||||
def runnable_status(self):
|
||||
"""
|
||||
Compute the task signature to make sure the scanner was executed. Create the
|
||||
moc tasks by using :py:meth:`waflib.Tools.qt4.qxx.add_moc_tasks` (if necessary),
|
||||
then postpone the task execution (there is no need to recompute the task signature).
|
||||
"""
|
||||
if self.moc_done:
|
||||
return Task.Task.runnable_status(self)
|
||||
else:
|
||||
for t in self.run_after:
|
||||
if not t.hasrun:
|
||||
return Task.ASK_LATER
|
||||
self.add_moc_tasks()
|
||||
return Task.Task.runnable_status(self)
|
||||
|
||||
def create_moc_task(self, h_node, m_node):
|
||||
"""
|
||||
If several libraries use the same classes, it is possible that moc will run several times (Issue 1318)
|
||||
It is not possible to change the file names, but we can assume that the moc transformation will be identical,
|
||||
and the moc tasks can be shared in a global cache.
|
||||
|
||||
The defines passed to moc will then depend on task generator order. If this is not acceptable, then
|
||||
use the tool slow_qt4 instead (and enjoy the slow builds... :-( )
|
||||
"""
|
||||
try:
|
||||
moc_cache = self.generator.bld.moc_cache
|
||||
except AttributeError:
|
||||
moc_cache = self.generator.bld.moc_cache = {}
|
||||
|
||||
try:
|
||||
return moc_cache[h_node]
|
||||
except KeyError:
|
||||
tsk = moc_cache[h_node] = Task.classes['moc'](env=self.env, generator=self.generator)
|
||||
tsk.set_inputs(h_node)
|
||||
tsk.set_outputs(m_node)
|
||||
|
||||
# direct injection in the build phase (safe because called from the main thread)
|
||||
gen = self.generator.bld.producer
|
||||
gen.outstanding.insert(0, tsk)
|
||||
gen.total += 1
|
||||
|
||||
return tsk
|
||||
|
||||
def add_moc_tasks(self):
|
||||
"""
|
||||
Create the moc tasks by looking in ``bld.raw_deps[self.uid()]``
|
||||
"""
|
||||
node = self.inputs[0]
|
||||
bld = self.generator.bld
|
||||
|
||||
try:
|
||||
# compute the signature once to know if there is a moc file to create
|
||||
self.signature()
|
||||
except KeyError:
|
||||
# the moc file may be referenced somewhere else
|
||||
pass
|
||||
else:
|
||||
# remove the signature, it must be recomputed with the moc task
|
||||
delattr(self, 'cache_sig')
|
||||
|
||||
moctasks=[]
|
||||
mocfiles=[]
|
||||
try:
|
||||
tmp_lst = bld.raw_deps[self.uid()]
|
||||
bld.raw_deps[self.uid()] = []
|
||||
except KeyError:
|
||||
tmp_lst = []
|
||||
for d in tmp_lst:
|
||||
if not d.endswith('.moc'):
|
||||
continue
|
||||
# paranoid check
|
||||
if d in mocfiles:
|
||||
Logs.error("paranoia owns")
|
||||
continue
|
||||
# process that base.moc only once
|
||||
mocfiles.append(d)
|
||||
|
||||
# find the extension - this search is done only once
|
||||
|
||||
h_node = None
|
||||
try: ext = Options.options.qt_header_ext.split()
|
||||
except AttributeError: pass
|
||||
if not ext: ext = MOC_H
|
||||
|
||||
base2 = d[:-4]
|
||||
for x in [node.parent] + self.generator.includes_nodes:
|
||||
for e in ext:
|
||||
h_node = x.find_node(base2 + e)
|
||||
if h_node:
|
||||
break
|
||||
if h_node:
|
||||
m_node = h_node.change_ext('.moc')
|
||||
break
|
||||
else:
|
||||
for k in EXT_QT4:
|
||||
if base2.endswith(k):
|
||||
for x in [node.parent] + self.generator.includes_nodes:
|
||||
h_node = x.find_node(base2)
|
||||
if h_node:
|
||||
break
|
||||
if h_node:
|
||||
m_node = h_node.change_ext(k + '.moc')
|
||||
break
|
||||
if not h_node:
|
||||
raise Errors.WafError('no header found for %r which is a moc file' % d)
|
||||
|
||||
# next time we will not search for the extension (look at the 'for' loop below)
|
||||
bld.node_deps[(self.inputs[0].parent.abspath(), m_node.name)] = h_node
|
||||
|
||||
# create the task
|
||||
task = self.create_moc_task(h_node, m_node)
|
||||
moctasks.append(task)
|
||||
|
||||
# remove raw deps except the moc files to save space (optimization)
|
||||
tmp_lst = bld.raw_deps[self.uid()] = mocfiles
|
||||
|
||||
# look at the file inputs, it is set right above
|
||||
lst = bld.node_deps.get(self.uid(), ())
|
||||
for d in lst:
|
||||
name = d.name
|
||||
if name.endswith('.moc'):
|
||||
task = self.create_moc_task(bld.node_deps[(self.inputs[0].parent.abspath(), name)], d)
|
||||
moctasks.append(task)
|
||||
|
||||
# simple scheduler dependency: run the moc task before others
|
||||
self.run_after.update(set(moctasks))
|
||||
self.moc_done = 1
|
||||
|
||||
run = Task.classes['cxx'].__dict__['run']
|
||||
|
||||
class trans_update(Task.Task):
|
||||
"""Update a .ts files from a list of C++ files"""
|
||||
run_str = '${QT_LUPDATE} ${SRC} -ts ${TGT}'
|
||||
color = 'BLUE'
|
||||
Task.update_outputs(trans_update)
|
||||
|
||||
class XMLHandler(ContentHandler):
|
||||
"""
|
||||
Parser for *.qrc* files
|
||||
"""
|
||||
def __init__(self):
|
||||
self.buf = []
|
||||
self.files = []
|
||||
def startElement(self, name, attrs):
|
||||
if name == 'file':
|
||||
self.buf = []
|
||||
def endElement(self, name):
|
||||
if name == 'file':
|
||||
self.files.append(str(''.join(self.buf)))
|
||||
def characters(self, cars):
|
||||
self.buf.append(cars)
|
||||
|
||||
@extension(*EXT_RCC)
|
||||
def create_rcc_task(self, node):
|
||||
"Create rcc and cxx tasks for *.qrc* files"
|
||||
rcnode = node.change_ext('_rc.cpp')
|
||||
rcctask = self.create_task('rcc', node, rcnode)
|
||||
cpptask = self.create_task('cxx', rcnode, rcnode.change_ext('.o'))
|
||||
try:
|
||||
self.compiled_tasks.append(cpptask)
|
||||
except AttributeError:
|
||||
self.compiled_tasks = [cpptask]
|
||||
return cpptask
|
||||
|
||||
@extension(*EXT_UI)
|
||||
def create_uic_task(self, node):
|
||||
"hook for uic tasks"
|
||||
uictask = self.create_task('ui4', node)
|
||||
uictask.outputs = [self.path.find_or_declare(self.env['ui_PATTERN'] % node.name[:-3])]
|
||||
|
||||
@extension('.ts')
|
||||
def add_lang(self, node):
|
||||
"""add all the .ts file into self.lang"""
|
||||
self.lang = self.to_list(getattr(self, 'lang', [])) + [node]
|
||||
|
||||
@feature('qt4')
|
||||
@after_method('apply_link')
|
||||
def apply_qt4(self):
|
||||
"""
|
||||
Add MOC_FLAGS which may be necessary for moc::
|
||||
|
||||
def build(bld):
|
||||
bld.program(features='qt4', source='main.cpp', target='app', use='QTCORE')
|
||||
|
||||
The additional parameters are:
|
||||
|
||||
:param lang: list of translation files (\*.ts) to process
|
||||
:type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension
|
||||
:param update: whether to process the C++ files to update the \*.ts files (use **waf --translate**)
|
||||
:type update: bool
|
||||
:param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file
|
||||
:type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension
|
||||
"""
|
||||
if getattr(self, 'lang', None):
|
||||
qmtasks = []
|
||||
for x in self.to_list(self.lang):
|
||||
if isinstance(x, str):
|
||||
x = self.path.find_resource(x + '.ts')
|
||||
qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm')))
|
||||
|
||||
if getattr(self, 'update', None) and Options.options.trans_qt4:
|
||||
cxxnodes = [a.inputs[0] for a in self.compiled_tasks] + [
|
||||
a.inputs[0] for a in self.tasks if getattr(a, 'inputs', None) and a.inputs[0].name.endswith('.ui')]
|
||||
for x in qmtasks:
|
||||
self.create_task('trans_update', cxxnodes, x.inputs)
|
||||
|
||||
if getattr(self, 'langname', None):
|
||||
qmnodes = [x.outputs[0] for x in qmtasks]
|
||||
rcnode = self.langname
|
||||
if isinstance(rcnode, str):
|
||||
rcnode = self.path.find_or_declare(rcnode + '.qrc')
|
||||
t = self.create_task('qm2rcc', qmnodes, rcnode)
|
||||
k = create_rcc_task(self, t.outputs[0])
|
||||
self.link_task.inputs.append(k.outputs[0])
|
||||
|
||||
lst = []
|
||||
for flag in self.to_list(self.env['CXXFLAGS']):
|
||||
if len(flag) < 2: continue
|
||||
f = flag[0:2]
|
||||
if f in ['-D', '-I', '/D', '/I']:
|
||||
if (f[0] == '/'):
|
||||
lst.append('-' + flag[1:])
|
||||
else:
|
||||
lst.append(flag)
|
||||
self.env.append_value('MOC_FLAGS', lst)
|
||||
|
||||
@extension(*EXT_QT4)
|
||||
def cxx_hook(self, node):
|
||||
"""
|
||||
Re-map C++ file extensions to the :py:class:`waflib.Tools.qt4.qxx` task.
|
||||
"""
|
||||
return self.create_compiled_task('qxx', node)
|
||||
|
||||
class rcc(Task.Task):
|
||||
"""
|
||||
Process *.qrc* files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_RCC} -name ${SRC[0].name} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'
|
||||
ext_out = ['.h']
|
||||
|
||||
def scan(self):
|
||||
"""Parse the *.qrc* files"""
|
||||
node = self.inputs[0]
|
||||
|
||||
if not has_xml:
|
||||
Logs.error('no xml support was found, the rcc dependencies will be incomplete!')
|
||||
return ([], [])
|
||||
|
||||
parser = make_parser()
|
||||
curHandler = XMLHandler()
|
||||
parser.setContentHandler(curHandler)
|
||||
fi = open(self.inputs[0].abspath(), 'r')
|
||||
try:
|
||||
parser.parse(fi)
|
||||
finally:
|
||||
fi.close()
|
||||
|
||||
nodes = []
|
||||
names = []
|
||||
root = self.inputs[0].parent
|
||||
for x in curHandler.files:
|
||||
nd = root.find_resource(x)
|
||||
if nd: nodes.append(nd)
|
||||
else: names.append(x)
|
||||
return (nodes, names)
|
||||
|
||||
class moc(Task.Task):
|
||||
"""
|
||||
Create *.moc* files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'
|
||||
|
||||
class ui4(Task.Task):
|
||||
"""
|
||||
Process *.ui* files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_UIC} ${SRC} -o ${TGT}'
|
||||
ext_out = ['.h']
|
||||
|
||||
class ts2qm(Task.Task):
|
||||
"""
|
||||
Create *.qm* files from *.ts* files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
|
||||
|
||||
class qm2rcc(Task.Task):
|
||||
"""
|
||||
Transform *.qm* files into *.rc* files
|
||||
"""
|
||||
color = 'BLUE'
|
||||
after = 'ts2qm'
|
||||
|
||||
def run(self):
|
||||
"""Create a qrc file including the inputs"""
|
||||
txt = '\n'.join(['<file>%s</file>' % k.path_from(self.outputs[0].parent) for k in self.inputs])
|
||||
code = '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt
|
||||
self.outputs[0].write(code)
|
||||
|
||||
def configure(self):
|
||||
"""
|
||||
Besides the configuration options, the environment variable QT4_ROOT may be used
|
||||
to give the location of the qt4 libraries (absolute path).
|
||||
|
||||
The detection will use the program *pkg-config* through :py:func:`waflib.Tools.config_c.check_cfg`
|
||||
"""
|
||||
self.find_qt4_binaries()
|
||||
self.set_qt4_libs_to_check()
|
||||
self.set_qt4_defines()
|
||||
self.find_qt4_libraries()
|
||||
self.add_qt4_rpath()
|
||||
self.simplify_qt4_libs()
|
||||
|
||||
@conf
|
||||
def find_qt4_binaries(self):
|
||||
env = self.env
|
||||
opt = Options.options
|
||||
|
||||
qtdir = getattr(opt, 'qtdir', '')
|
||||
qtbin = getattr(opt, 'qtbin', '')
|
||||
|
||||
paths = []
|
||||
|
||||
if qtdir:
|
||||
qtbin = os.path.join(qtdir, 'bin')
|
||||
|
||||
# the qt directory has been given from QT4_ROOT - deduce the qt binary path
|
||||
if not qtdir:
|
||||
qtdir = os.environ.get('QT4_ROOT', '')
|
||||
qtbin = os.environ.get('QT4_BIN', None) or os.path.join(qtdir, 'bin')
|
||||
|
||||
if qtbin:
|
||||
paths = [qtbin]
|
||||
|
||||
# no qtdir, look in the path and in /usr/local/Trolltech
|
||||
if not qtdir:
|
||||
paths = os.environ.get('PATH', '').split(os.pathsep)
|
||||
paths.append('/usr/share/qt4/bin/')
|
||||
try:
|
||||
lst = Utils.listdir('/usr/local/Trolltech/')
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
if lst:
|
||||
lst.sort()
|
||||
lst.reverse()
|
||||
|
||||
# keep the highest version
|
||||
qtdir = '/usr/local/Trolltech/%s/' % lst[0]
|
||||
qtbin = os.path.join(qtdir, 'bin')
|
||||
paths.append(qtbin)
|
||||
|
||||
# at the end, try to find qmake in the paths given
|
||||
# keep the one with the highest version
|
||||
cand = None
|
||||
prev_ver = ['4', '0', '0']
|
||||
for qmk in ['qmake-qt4', 'qmake4', 'qmake']:
|
||||
try:
|
||||
qmake = self.find_program(qmk, path_list=paths)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
version = self.cmd_and_log([qmake, '-query', 'QT_VERSION']).strip()
|
||||
except self.errors.WafError:
|
||||
pass
|
||||
else:
|
||||
if version:
|
||||
new_ver = version.split('.')
|
||||
if new_ver > prev_ver:
|
||||
cand = qmake
|
||||
prev_ver = new_ver
|
||||
if cand:
|
||||
self.env.QMAKE = cand
|
||||
else:
|
||||
self.fatal('Could not find qmake for qt4')
|
||||
|
||||
qtbin = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_BINS']).strip() + os.sep
|
||||
|
||||
def find_bin(lst, var):
|
||||
if var in env:
|
||||
return
|
||||
for f in lst:
|
||||
try:
|
||||
ret = self.find_program(f, path_list=paths)
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
else:
|
||||
env[var]=ret
|
||||
break
|
||||
|
||||
find_bin(['uic-qt3', 'uic3'], 'QT_UIC3')
|
||||
find_bin(['uic-qt4', 'uic'], 'QT_UIC')
|
||||
if not env['QT_UIC']:
|
||||
self.fatal('cannot find the uic compiler for qt4')
|
||||
|
||||
try:
|
||||
uicver = self.cmd_and_log(env['QT_UIC'] + " -version 2>&1").strip()
|
||||
except self.errors.ConfigurationError:
|
||||
self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')
|
||||
uicver = uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '')
|
||||
self.msg('Checking for uic version', '%s' % uicver)
|
||||
if uicver.find(' 3.') != -1:
|
||||
self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')
|
||||
|
||||
find_bin(['moc-qt4', 'moc'], 'QT_MOC')
|
||||
find_bin(['rcc'], 'QT_RCC')
|
||||
find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE')
|
||||
find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE')
|
||||
|
||||
env['UIC3_ST']= '%s -o %s'
|
||||
env['UIC_ST'] = '%s -o %s'
|
||||
env['MOC_ST'] = '-o'
|
||||
env['ui_PATTERN'] = 'ui_%s.h'
|
||||
env['QT_LRELEASE_FLAGS'] = ['-silent']
|
||||
env.MOCCPPPATH_ST = '-I%s'
|
||||
env.MOCDEFINES_ST = '-D%s'
|
||||
|
||||
@conf
|
||||
def find_qt4_libraries(self):
|
||||
qtlibs = getattr(Options.options, 'qtlibs', None) or os.environ.get("QT4_LIBDIR", None)
|
||||
if not qtlibs:
|
||||
try:
|
||||
qtlibs = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_LIBS']).strip()
|
||||
except Errors.WafError:
|
||||
qtdir = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_PREFIX']).strip() + os.sep
|
||||
qtlibs = os.path.join(qtdir, 'lib')
|
||||
self.msg('Found the Qt4 libraries in', qtlibs)
|
||||
|
||||
qtincludes = os.environ.get("QT4_INCLUDES", None) or self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_HEADERS']).strip()
|
||||
env = self.env
|
||||
if not 'PKG_CONFIG_PATH' in os.environ:
|
||||
os.environ['PKG_CONFIG_PATH'] = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs)
|
||||
|
||||
try:
|
||||
if os.environ.get("QT4_XCOMPILE", None):
|
||||
raise self.errors.ConfigurationError()
|
||||
self.check_cfg(atleast_pkgconfig_version='0.1')
|
||||
except self.errors.ConfigurationError:
|
||||
for i in self.qt4_vars:
|
||||
uselib = i.upper()
|
||||
if Utils.unversioned_sys_platform() == "darwin":
|
||||
# Since at least qt 4.7.3 each library locates in separate directory
|
||||
frameworkName = i + ".framework"
|
||||
qtDynamicLib = os.path.join(qtlibs, frameworkName, i)
|
||||
if os.path.exists(qtDynamicLib):
|
||||
env.append_unique('FRAMEWORK_' + uselib, i)
|
||||
self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')
|
||||
else:
|
||||
self.msg('Checking for %s' % i, False, 'YELLOW')
|
||||
env.append_unique('INCLUDES_' + uselib, os.path.join(qtlibs, frameworkName, 'Headers'))
|
||||
elif env.DEST_OS != "win32":
|
||||
qtDynamicLib = os.path.join(qtlibs, "lib" + i + ".so")
|
||||
qtStaticLib = os.path.join(qtlibs, "lib" + i + ".a")
|
||||
if os.path.exists(qtDynamicLib):
|
||||
env.append_unique('LIB_' + uselib, i)
|
||||
self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')
|
||||
elif os.path.exists(qtStaticLib):
|
||||
env.append_unique('LIB_' + uselib, i)
|
||||
self.msg('Checking for %s' % i, qtStaticLib, 'GREEN')
|
||||
else:
|
||||
self.msg('Checking for %s' % i, False, 'YELLOW')
|
||||
|
||||
env.append_unique('LIBPATH_' + uselib, qtlibs)
|
||||
env.append_unique('INCLUDES_' + uselib, qtincludes)
|
||||
env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
|
||||
else:
|
||||
# Release library names are like QtCore4
|
||||
for k in ("lib%s.a", "lib%s4.a", "%s.lib", "%s4.lib"):
|
||||
lib = os.path.join(qtlibs, k % i)
|
||||
if os.path.exists(lib):
|
||||
env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])
|
||||
self.msg('Checking for %s' % i, lib, 'GREEN')
|
||||
break
|
||||
else:
|
||||
self.msg('Checking for %s' % i, False, 'YELLOW')
|
||||
|
||||
env.append_unique('LIBPATH_' + uselib, qtlibs)
|
||||
env.append_unique('INCLUDES_' + uselib, qtincludes)
|
||||
env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
|
||||
|
||||
# Debug library names are like QtCore4d
|
||||
uselib = i.upper() + "_debug"
|
||||
for k in ("lib%sd.a", "lib%sd4.a", "%sd.lib", "%sd4.lib"):
|
||||
lib = os.path.join(qtlibs, k % i)
|
||||
if os.path.exists(lib):
|
||||
env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])
|
||||
self.msg('Checking for %s' % i, lib, 'GREEN')
|
||||
break
|
||||
else:
|
||||
self.msg('Checking for %s' % i, False, 'YELLOW')
|
||||
|
||||
env.append_unique('LIBPATH_' + uselib, qtlibs)
|
||||
env.append_unique('INCLUDES_' + uselib, qtincludes)
|
||||
env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
|
||||
else:
|
||||
for i in self.qt4_vars_debug + self.qt4_vars:
|
||||
self.check_cfg(package=i, args='--cflags --libs', mandatory=False)
|
||||
|
||||
@conf
|
||||
def simplify_qt4_libs(self):
|
||||
# the libpaths make really long command-lines
|
||||
# remove the qtcore ones from qtgui, etc
|
||||
env = self.env
|
||||
def process_lib(vars_, coreval):
|
||||
for d in vars_:
|
||||
var = d.upper()
|
||||
if var == 'QTCORE':
|
||||
continue
|
||||
|
||||
value = env['LIBPATH_'+var]
|
||||
if value:
|
||||
core = env[coreval]
|
||||
accu = []
|
||||
for lib in value:
|
||||
if lib in core:
|
||||
continue
|
||||
accu.append(lib)
|
||||
env['LIBPATH_'+var] = accu
|
||||
|
||||
process_lib(self.qt4_vars, 'LIBPATH_QTCORE')
|
||||
process_lib(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')
|
||||
|
||||
@conf
|
||||
def add_qt4_rpath(self):
|
||||
# rpath if wanted
|
||||
env = self.env
|
||||
if getattr(Options.options, 'want_rpath', False):
|
||||
def process_rpath(vars_, coreval):
|
||||
for d in vars_:
|
||||
var = d.upper()
|
||||
value = env['LIBPATH_'+var]
|
||||
if value:
|
||||
core = env[coreval]
|
||||
accu = []
|
||||
for lib in value:
|
||||
if var != 'QTCORE':
|
||||
if lib in core:
|
||||
continue
|
||||
accu.append('-Wl,--rpath='+lib)
|
||||
env['RPATH_'+var] = accu
|
||||
process_rpath(self.qt4_vars, 'LIBPATH_QTCORE')
|
||||
process_rpath(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')
|
||||
|
||||
@conf
|
||||
def set_qt4_libs_to_check(self):
|
||||
if not hasattr(self, 'qt4_vars'):
|
||||
self.qt4_vars = QT4_LIBS
|
||||
self.qt4_vars = Utils.to_list(self.qt4_vars)
|
||||
if not hasattr(self, 'qt4_vars_debug'):
|
||||
self.qt4_vars_debug = [a + '_debug' for a in self.qt4_vars]
|
||||
self.qt4_vars_debug = Utils.to_list(self.qt4_vars_debug)
|
||||
|
||||
@conf
|
||||
def set_qt4_defines(self):
|
||||
if sys.platform != 'win32':
|
||||
return
|
||||
for x in self.qt4_vars:
|
||||
y = x[2:].upper()
|
||||
self.env.append_unique('DEFINES_%s' % x.upper(), 'QT_%s_LIB' % y)
|
||||
self.env.append_unique('DEFINES_%s_DEBUG' % x.upper(), 'QT_%s_LIB' % y)
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Command-line options
|
||||
"""
|
||||
opt.add_option('--want-rpath', action='store_true', default=False, dest='want_rpath', help='enable the rpath for qt libraries')
|
||||
|
||||
opt.add_option('--header-ext',
|
||||
type='string',
|
||||
default='',
|
||||
help='header extension for moc files',
|
||||
dest='qt_header_ext')
|
||||
|
||||
for i in 'qtdir qtbin qtlibs'.split():
|
||||
opt.add_option('--'+i, type='string', default='', dest=i)
|
||||
|
||||
opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False)
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# daniel.svensson at purplescout.se 2008
|
||||
# Thomas Nagy 2010 (ita)
|
||||
|
||||
"""
|
||||
Support for Ruby extensions. A C/C++ compiler is required::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_c ruby')
|
||||
def configure(conf):
|
||||
conf.load('compiler_c ruby')
|
||||
conf.check_ruby_version((1,8,0))
|
||||
conf.check_ruby_ext_devel()
|
||||
conf.check_ruby_module('libxml')
|
||||
def build(bld):
|
||||
bld(
|
||||
features = 'c cshlib rubyext',
|
||||
source = 'rb_mytest.c',
|
||||
target = 'mytest_ext',
|
||||
install_path = '${ARCHDIR_RUBY}')
|
||||
bld.install_files('${LIBDIR_RUBY}', 'Mytest.rb')
|
||||
"""
|
||||
|
||||
import os
|
||||
from waflib import Task, Options, Utils
|
||||
from waflib.TaskGen import before_method, feature, after_method, Task, extension
|
||||
from waflib.Configure import conf
|
||||
|
||||
@feature('rubyext')
|
||||
@before_method('apply_incpaths', 'apply_lib_vars', 'apply_bundle', 'apply_link')
|
||||
def init_rubyext(self):
|
||||
"""
|
||||
Add required variables for ruby extensions
|
||||
"""
|
||||
self.install_path = '${ARCHDIR_RUBY}'
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', ''))
|
||||
if not 'RUBY' in self.uselib:
|
||||
self.uselib.append('RUBY')
|
||||
if not 'RUBYEXT' in self.uselib:
|
||||
self.uselib.append('RUBYEXT')
|
||||
|
||||
@feature('rubyext')
|
||||
@before_method('apply_link', 'propagate_uselib')
|
||||
def apply_ruby_so_name(self):
|
||||
"""
|
||||
Strip the *lib* prefix from ruby extensions
|
||||
"""
|
||||
self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['rubyext_PATTERN']
|
||||
|
||||
@conf
|
||||
def check_ruby_version(self, minver=()):
|
||||
"""
|
||||
Checks if ruby is installed.
|
||||
If installed the variable RUBY will be set in environment.
|
||||
The ruby binary can be overridden by ``--with-ruby-binary`` command-line option.
|
||||
"""
|
||||
|
||||
if Options.options.rubybinary:
|
||||
self.env.RUBY = Options.options.rubybinary
|
||||
else:
|
||||
self.find_program('ruby', var='RUBY')
|
||||
|
||||
ruby = self.env.RUBY
|
||||
|
||||
try:
|
||||
version = self.cmd_and_log([ruby, '-e', 'puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip()
|
||||
except Exception:
|
||||
self.fatal('could not determine ruby version')
|
||||
self.env.RUBY_VERSION = version
|
||||
|
||||
try:
|
||||
ver = tuple(map(int, version.split(".")))
|
||||
except Exception:
|
||||
self.fatal('unsupported ruby version %r' % version)
|
||||
|
||||
cver = ''
|
||||
if minver:
|
||||
if ver < minver:
|
||||
self.fatal('ruby is too old %r' % ver)
|
||||
cver = '.'.join([str(x) for x in minver])
|
||||
else:
|
||||
cver = ver
|
||||
|
||||
self.msg('Checking for ruby version %s' % str(minver or ''), cver)
|
||||
|
||||
@conf
|
||||
def check_ruby_ext_devel(self):
|
||||
"""
|
||||
Check if a ruby extension can be created
|
||||
"""
|
||||
if not self.env.RUBY:
|
||||
self.fatal('ruby detection is required first')
|
||||
|
||||
if not self.env.CC_NAME and not self.env.CXX_NAME:
|
||||
self.fatal('load a c/c++ compiler first')
|
||||
|
||||
version = tuple(map(int, self.env.RUBY_VERSION.split(".")))
|
||||
|
||||
def read_out(cmd):
|
||||
return Utils.to_list(self.cmd_and_log([self.env.RUBY, '-rrbconfig', '-e', cmd]))
|
||||
|
||||
def read_config(key):
|
||||
return read_out('puts Config::CONFIG[%r]' % key)
|
||||
|
||||
ruby = self.env['RUBY']
|
||||
archdir = read_config('archdir')
|
||||
cpppath = archdir
|
||||
|
||||
if version >= (1, 9, 0):
|
||||
ruby_hdrdir = read_config('rubyhdrdir')
|
||||
cpppath += ruby_hdrdir
|
||||
cpppath += [os.path.join(ruby_hdrdir[0], read_config('arch')[0])]
|
||||
|
||||
self.check(header_name='ruby.h', includes=cpppath, errmsg='could not find ruby header file')
|
||||
|
||||
self.env.LIBPATH_RUBYEXT = read_config('libdir')
|
||||
self.env.LIBPATH_RUBYEXT += archdir
|
||||
self.env.INCLUDES_RUBYEXT = cpppath
|
||||
self.env.CFLAGS_RUBYEXT = read_config('CCDLFLAGS')
|
||||
self.env.rubyext_PATTERN = '%s.' + read_config('DLEXT')[0]
|
||||
|
||||
# ok this is really stupid, but the command and flags are combined.
|
||||
# so we try to find the first argument...
|
||||
flags = read_config('LDSHARED')
|
||||
while flags and flags[0][0] != '-':
|
||||
flags = flags[1:]
|
||||
|
||||
# we also want to strip out the deprecated ppc flags
|
||||
if len(flags) > 1 and flags[1] == "ppc":
|
||||
flags = flags[2:]
|
||||
|
||||
self.env.LINKFLAGS_RUBYEXT = flags
|
||||
self.env.LINKFLAGS_RUBYEXT += read_config('LIBS')
|
||||
self.env.LINKFLAGS_RUBYEXT += read_config('LIBRUBYARG_SHARED')
|
||||
|
||||
if Options.options.rubyarchdir:
|
||||
self.env.ARCHDIR_RUBY = Options.options.rubyarchdir
|
||||
else:
|
||||
self.env.ARCHDIR_RUBY = read_config('sitearchdir')[0]
|
||||
|
||||
if Options.options.rubylibdir:
|
||||
self.env.LIBDIR_RUBY = Options.options.rubylibdir
|
||||
else:
|
||||
self.env.LIBDIR_RUBY = read_config('sitelibdir')[0]
|
||||
|
||||
@conf
|
||||
def check_ruby_module(self, module_name):
|
||||
"""
|
||||
Check if the selected ruby interpreter can require the given ruby module::
|
||||
|
||||
def configure(conf):
|
||||
conf.check_ruby_module('libxml')
|
||||
|
||||
:param module_name: module
|
||||
:type module_name: string
|
||||
"""
|
||||
self.start_msg('Ruby module %s' % module_name)
|
||||
try:
|
||||
self.cmd_and_log([self.env['RUBY'], '-e', 'require \'%s\';puts 1' % module_name])
|
||||
except Exception:
|
||||
self.end_msg(False)
|
||||
self.fatal('Could not find the ruby module %r' % module_name)
|
||||
self.end_msg(True)
|
||||
|
||||
@extension('.rb')
|
||||
def process(self, node):
|
||||
tsk = self.create_task('run_ruby', node)
|
||||
|
||||
class run_ruby(Task.Task):
|
||||
"""
|
||||
Task to run ruby files detected by file extension .rb::
|
||||
|
||||
def options(opt):
|
||||
opt.load('ruby')
|
||||
|
||||
def configure(ctx):
|
||||
ctx.check_ruby_version()
|
||||
|
||||
def build(bld):
|
||||
bld.env['RBFLAGS'] = '-e puts "hello world"'
|
||||
bld(source='a_ruby_file.rb')
|
||||
"""
|
||||
run_str = '${RUBY} ${RBFLAGS} -I ${SRC[0].parent.abspath()} ${SRC}'
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Add the ``--with-ruby-archdir``, ``--with-ruby-libdir`` and ``--with-ruby-binary`` options
|
||||
"""
|
||||
opt.add_option('--with-ruby-archdir', type='string', dest='rubyarchdir', help='Specify directory where to install arch specific files')
|
||||
opt.add_option('--with-ruby-libdir', type='string', dest='rubylibdir', help='Specify alternate ruby library path')
|
||||
opt.add_option('--with-ruby-binary', type='string', dest='rubybinary', help='Specify alternate ruby binary')
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
|
||||
import os
|
||||
from waflib import Utils
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_scc(conf):
|
||||
"""
|
||||
Detect the Sun C compiler
|
||||
"""
|
||||
v = conf.env
|
||||
cc = None
|
||||
if v['CC']: cc = v['CC']
|
||||
elif 'CC' in conf.environ: cc = conf.environ['CC']
|
||||
if not cc: cc = conf.find_program('cc', var='CC')
|
||||
if not cc: conf.fatal('Could not find a Sun C compiler')
|
||||
cc = conf.cmd_to_list(cc)
|
||||
|
||||
try:
|
||||
conf.cmd_and_log(cc + ['-flags'])
|
||||
except Exception:
|
||||
conf.fatal('%r is not a Sun compiler' % cc)
|
||||
|
||||
v['CC'] = cc
|
||||
v['CC_NAME'] = 'sun'
|
||||
|
||||
@conf
|
||||
def scc_common_flags(conf):
|
||||
"""
|
||||
Flags required for executing the sun C compiler
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['CC_SRC_F'] = []
|
||||
v['CC_TGT_F'] = ['-c', '-o']
|
||||
|
||||
# linker
|
||||
if not v['LINK_CC']: v['LINK_CC'] = v['CC']
|
||||
v['CCLNK_SRC_F'] = ''
|
||||
v['CCLNK_TGT_F'] = ['-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
|
||||
v['SONAME_ST'] = '-Wl,-h,%s'
|
||||
v['SHLIB_MARKER'] = '-Bdynamic'
|
||||
v['STLIB_MARKER'] = '-Bstatic'
|
||||
|
||||
# program
|
||||
v['cprogram_PATTERN'] = '%s'
|
||||
|
||||
# shared library
|
||||
v['CFLAGS_cshlib'] = ['-Kpic', '-DPIC']
|
||||
v['LINKFLAGS_cshlib'] = ['-G']
|
||||
v['cshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
# static lib
|
||||
v['LINKFLAGS_cstlib'] = ['-Bstatic']
|
||||
v['cstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_scc()
|
||||
conf.find_ar()
|
||||
conf.scc_common_flags()
|
||||
conf.cc_load_tools()
|
||||
conf.cc_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
|
||||
import os
|
||||
from waflib import Utils
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_sxx(conf):
|
||||
"""
|
||||
Detect the sun C++ compiler
|
||||
"""
|
||||
v = conf.env
|
||||
cc = None
|
||||
if v['CXX']: cc = v['CXX']
|
||||
elif 'CXX' in conf.environ: cc = conf.environ['CXX']
|
||||
if not cc: cc = conf.find_program('CC', var='CXX') #studio
|
||||
if not cc: cc = conf.find_program('c++', var='CXX')
|
||||
if not cc: conf.fatal('Could not find a Sun C++ compiler')
|
||||
cc = conf.cmd_to_list(cc)
|
||||
|
||||
try:
|
||||
conf.cmd_and_log(cc + ['-flags'])
|
||||
except Exception:
|
||||
conf.fatal('%r is not a Sun compiler' % cc)
|
||||
|
||||
v['CXX'] = cc
|
||||
v['CXX_NAME'] = 'sun'
|
||||
|
||||
@conf
|
||||
def sxx_common_flags(conf):
|
||||
"""
|
||||
Flags required for executing the sun C++ compiler
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['CXX_SRC_F'] = []
|
||||
v['CXX_TGT_F'] = ['-c', '-o']
|
||||
|
||||
# linker
|
||||
if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']
|
||||
v['CXXLNK_SRC_F'] = []
|
||||
v['CXXLNK_TGT_F'] = ['-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
|
||||
v['SONAME_ST'] = '-Wl,-h,%s'
|
||||
v['SHLIB_MARKER'] = '-Bdynamic'
|
||||
v['STLIB_MARKER'] = '-Bstatic'
|
||||
|
||||
# program
|
||||
v['cxxprogram_PATTERN'] = '%s'
|
||||
|
||||
# shared library
|
||||
v['CXXFLAGS_cxxshlib'] = ['-Kpic', '-DPIC']
|
||||
v['LINKFLAGS_cxxshlib'] = ['-G']
|
||||
v['cxxshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
# static lib
|
||||
v['LINKFLAGS_cxxstlib'] = ['-Bstatic']
|
||||
v['cxxstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_sxx()
|
||||
conf.find_ar()
|
||||
conf.sxx_common_flags()
|
||||
conf.cxx_load_tools()
|
||||
conf.cxx_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
+431
@@ -0,0 +1,431 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
|
||||
"""
|
||||
TeX/LaTeX/PDFLaTeX/XeLaTeX support
|
||||
|
||||
Example::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('tex')
|
||||
if not conf.env.LATEX:
|
||||
conf.fatal('The program LaTex is required')
|
||||
|
||||
def build(bld):
|
||||
bld(
|
||||
features = 'tex',
|
||||
type = 'latex', # pdflatex or xelatex
|
||||
source = 'document.ltx', # mandatory, the source
|
||||
outs = 'ps', # 'pdf' or 'ps pdf'
|
||||
deps = 'crossreferencing.lst', # to give dependencies directly
|
||||
prompt = 1, # 0 for the batch mode
|
||||
)
|
||||
|
||||
To configure with a special program use::
|
||||
|
||||
$ PDFLATEX=luatex waf configure
|
||||
"""
|
||||
|
||||
import os, re
|
||||
from waflib import Utils, Task, Errors, Logs
|
||||
from waflib.TaskGen import feature, before_method
|
||||
|
||||
re_bibunit = re.compile(r'\\(?P<type>putbib)\[(?P<file>[^\[\]]*)\]',re.M)
|
||||
def bibunitscan(self):
|
||||
"""
|
||||
Parse the inputs and try to find the *bibunit* dependencies
|
||||
|
||||
:return: list of bibunit files
|
||||
:rtype: list of :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
node = self.inputs[0]
|
||||
|
||||
nodes = []
|
||||
if not node: return nodes
|
||||
|
||||
code = node.read()
|
||||
|
||||
for match in re_bibunit.finditer(code):
|
||||
path = match.group('file')
|
||||
if path:
|
||||
for k in ['', '.bib']:
|
||||
# add another loop for the tex include paths?
|
||||
Logs.debug('tex: trying %s%s' % (path, k))
|
||||
fi = node.parent.find_resource(path + k)
|
||||
if fi:
|
||||
nodes.append(fi)
|
||||
# no break, people are crazy
|
||||
else:
|
||||
Logs.debug('tex: could not find %s' % path)
|
||||
|
||||
Logs.debug("tex: found the following bibunit files: %s" % nodes)
|
||||
return nodes
|
||||
|
||||
exts_deps_tex = ['', '.ltx', '.tex', '.bib', '.pdf', '.png', '.eps', '.ps']
|
||||
"""List of typical file extensions included in latex files"""
|
||||
|
||||
exts_tex = ['.ltx', '.tex']
|
||||
"""List of typical file extensions that contain latex"""
|
||||
|
||||
re_tex = re.compile(r'\\(?P<type>include|bibliography|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P<file>[^{}]*)}',re.M)
|
||||
"""Regexp for expressions that may include latex files"""
|
||||
|
||||
g_bibtex_re = re.compile('bibdata', re.M)
|
||||
"""Regexp for bibtex files"""
|
||||
|
||||
class tex(Task.Task):
|
||||
"""
|
||||
Compile a tex/latex file.
|
||||
|
||||
.. inheritance-diagram:: waflib.Tools.tex.latex waflib.Tools.tex.xelatex waflib.Tools.tex.pdflatex
|
||||
"""
|
||||
|
||||
bibtex_fun, _ = Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}', shell=False)
|
||||
bibtex_fun.__doc__ = """
|
||||
Execute the program **bibtex**
|
||||
"""
|
||||
|
||||
makeindex_fun, _ = Task.compile_fun('${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}', shell=False)
|
||||
makeindex_fun.__doc__ = """
|
||||
Execute the program **makeindex**
|
||||
"""
|
||||
|
||||
def exec_command(self, cmd, **kw):
|
||||
"""
|
||||
Override :py:meth:`waflib.Task.Task.exec_command` to execute the command without buffering (latex may prompt for inputs)
|
||||
|
||||
:return: the return code
|
||||
:rtype: int
|
||||
"""
|
||||
bld = self.generator.bld
|
||||
try:
|
||||
if not kw.get('cwd', None):
|
||||
kw['cwd'] = bld.cwd
|
||||
except AttributeError:
|
||||
bld.cwd = kw['cwd'] = bld.variant_dir
|
||||
return Utils.subprocess.Popen(cmd, **kw).wait()
|
||||
|
||||
def scan_aux(self, node):
|
||||
"""
|
||||
A recursive regex-based scanner that finds included auxiliary files.
|
||||
"""
|
||||
nodes = [node]
|
||||
re_aux = re.compile(r'\\@input{(?P<file>[^{}]*)}', re.M)
|
||||
|
||||
def parse_node(node):
|
||||
code = node.read()
|
||||
for match in re_aux.finditer(code):
|
||||
path = match.group('file')
|
||||
found = node.parent.find_or_declare(path)
|
||||
if found and found not in nodes:
|
||||
Logs.debug('tex: found aux node ' + found.abspath())
|
||||
nodes.append(found)
|
||||
parse_node(found)
|
||||
|
||||
parse_node(node)
|
||||
return nodes
|
||||
|
||||
def scan(self):
|
||||
"""
|
||||
A recursive regex-based scanner that finds latex dependencies. It uses :py:attr:`waflib.Tools.tex.re_tex`
|
||||
|
||||
Depending on your needs you might want:
|
||||
|
||||
* to change re_tex::
|
||||
|
||||
from waflib.Tools import tex
|
||||
tex.re_tex = myregex
|
||||
|
||||
* or to change the method scan from the latex tasks::
|
||||
|
||||
from waflib.Task import classes
|
||||
classes['latex'].scan = myscanfunction
|
||||
"""
|
||||
node = self.inputs[0]
|
||||
|
||||
nodes = []
|
||||
names = []
|
||||
seen = []
|
||||
if not node: return (nodes, names)
|
||||
|
||||
def parse_node(node):
|
||||
if node in seen:
|
||||
return
|
||||
seen.append(node)
|
||||
code = node.read()
|
||||
global re_tex
|
||||
for match in re_tex.finditer(code):
|
||||
for path in match.group('file').split(','):
|
||||
if path:
|
||||
add_name = True
|
||||
found = None
|
||||
for k in exts_deps_tex:
|
||||
Logs.debug('tex: trying %s%s' % (path, k))
|
||||
found = node.parent.find_resource(path + k)
|
||||
|
||||
for tsk in self.generator.tasks:
|
||||
if not found or found in tsk.outputs:
|
||||
break
|
||||
else:
|
||||
nodes.append(found)
|
||||
add_name = False
|
||||
for ext in exts_tex:
|
||||
if found.name.endswith(ext):
|
||||
parse_node(found)
|
||||
break
|
||||
# no break, people are crazy
|
||||
if add_name:
|
||||
names.append(path)
|
||||
parse_node(node)
|
||||
|
||||
for x in nodes:
|
||||
x.parent.get_bld().mkdir()
|
||||
|
||||
Logs.debug("tex: found the following : %s and names %s" % (nodes, names))
|
||||
return (nodes, names)
|
||||
|
||||
def check_status(self, msg, retcode):
|
||||
"""
|
||||
Check an exit status and raise an error with a particular message
|
||||
|
||||
:param msg: message to display if the code is non-zero
|
||||
:type msg: string
|
||||
:param retcode: condition
|
||||
:type retcode: boolean
|
||||
"""
|
||||
if retcode != 0:
|
||||
raise Errors.WafError("%r command exit status %r" % (msg, retcode))
|
||||
|
||||
def bibfile(self):
|
||||
"""
|
||||
Parse the *.aux* files to find bibfiles to process.
|
||||
If yes, execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun`
|
||||
"""
|
||||
for aux_node in self.aux_nodes:
|
||||
try:
|
||||
ct = aux_node.read()
|
||||
except (OSError, IOError):
|
||||
Logs.error('Error reading %s: %r' % aux_node.abspath())
|
||||
continue
|
||||
|
||||
if g_bibtex_re.findall(ct):
|
||||
Logs.warn('calling bibtex')
|
||||
|
||||
self.env.env = {}
|
||||
self.env.env.update(os.environ)
|
||||
self.env.env.update({'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS})
|
||||
self.env.SRCFILE = aux_node.name[:-4]
|
||||
self.check_status('error when calling bibtex', self.bibtex_fun())
|
||||
|
||||
def bibunits(self):
|
||||
"""
|
||||
Parse the *.aux* file to find bibunit files. If there are bibunit files,
|
||||
execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun`.
|
||||
"""
|
||||
try:
|
||||
bibunits = bibunitscan(self)
|
||||
except OSError:
|
||||
Logs.error('error bibunitscan')
|
||||
else:
|
||||
if bibunits:
|
||||
fn = ['bu' + str(i) for i in xrange(1, len(bibunits) + 1)]
|
||||
if fn:
|
||||
Logs.warn('calling bibtex on bibunits')
|
||||
|
||||
for f in fn:
|
||||
self.env.env = {'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS}
|
||||
self.env.SRCFILE = f
|
||||
self.check_status('error when calling bibtex', self.bibtex_fun())
|
||||
|
||||
def makeindex(self):
|
||||
"""
|
||||
Look on the filesystem if there is a *.idx* file to process. If yes, execute
|
||||
:py:meth:`waflib.Tools.tex.tex.makeindex_fun`
|
||||
"""
|
||||
try:
|
||||
idx_path = self.idx_node.abspath()
|
||||
os.stat(idx_path)
|
||||
except OSError:
|
||||
Logs.warn('index file %s absent, not calling makeindex' % idx_path)
|
||||
else:
|
||||
Logs.warn('calling makeindex')
|
||||
|
||||
self.env.SRCFILE = self.idx_node.name
|
||||
self.env.env = {}
|
||||
self.check_status('error when calling makeindex %s' % idx_path, self.makeindex_fun())
|
||||
|
||||
def bibtopic(self):
|
||||
"""
|
||||
Additional .aux files from the bibtopic package
|
||||
"""
|
||||
p = self.inputs[0].parent.get_bld()
|
||||
if os.path.exists(os.path.join(p.abspath(), 'btaux.aux')):
|
||||
self.aux_nodes += p.ant_glob('*[0-9].aux')
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Runs the TeX build process.
|
||||
|
||||
It may require multiple passes, depending on the usage of cross-references,
|
||||
bibliographies, content susceptible of needing such passes.
|
||||
The appropriate TeX compiler is called until the *.aux* files stop changing.
|
||||
|
||||
Makeindex and bibtex are called if necessary.
|
||||
"""
|
||||
env = self.env
|
||||
|
||||
if not env['PROMPT_LATEX']:
|
||||
env.append_value('LATEXFLAGS', '-interaction=batchmode')
|
||||
env.append_value('PDFLATEXFLAGS', '-interaction=batchmode')
|
||||
env.append_value('XELATEXFLAGS', '-interaction=batchmode')
|
||||
|
||||
fun = self.texfun
|
||||
|
||||
node = self.inputs[0]
|
||||
srcfile = node.abspath()
|
||||
|
||||
texinputs = self.env.TEXINPUTS or ''
|
||||
self.TEXINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep + texinputs + os.pathsep
|
||||
|
||||
# important, set the cwd for everybody
|
||||
self.cwd = self.inputs[0].parent.get_bld().abspath()
|
||||
|
||||
Logs.warn('first pass on %s' % self.__class__.__name__)
|
||||
|
||||
self.env.env = {}
|
||||
self.env.env.update(os.environ)
|
||||
self.env.env.update({'TEXINPUTS': self.TEXINPUTS})
|
||||
self.env.SRCFILE = srcfile
|
||||
self.check_status('error when calling latex', fun())
|
||||
|
||||
self.aux_nodes = self.scan_aux(node.change_ext('.aux'))
|
||||
self.idx_node = node.change_ext('.idx')
|
||||
|
||||
self.bibtopic()
|
||||
self.bibfile()
|
||||
self.bibunits()
|
||||
self.makeindex()
|
||||
|
||||
hash = ''
|
||||
for i in range(10):
|
||||
# prevent against infinite loops - one never knows
|
||||
|
||||
# watch the contents of file.aux and stop if file.aux does not change anymore
|
||||
prev_hash = hash
|
||||
try:
|
||||
hashes = [Utils.h_file(x.abspath()) for x in self.aux_nodes]
|
||||
hash = Utils.h_list(hashes)
|
||||
except (OSError, IOError):
|
||||
Logs.error('could not read aux.h')
|
||||
pass
|
||||
if hash and hash == prev_hash:
|
||||
break
|
||||
|
||||
# run the command
|
||||
Logs.warn('calling %s' % self.__class__.__name__)
|
||||
|
||||
self.env.env = {}
|
||||
self.env.env.update(os.environ)
|
||||
self.env.env.update({'TEXINPUTS': self.TEXINPUTS})
|
||||
self.env.SRCFILE = srcfile
|
||||
self.check_status('error when calling %s' % self.__class__.__name__, fun())
|
||||
|
||||
class latex(tex):
|
||||
texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False)
|
||||
class pdflatex(tex):
|
||||
texfun, vars = Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False)
|
||||
class xelatex(tex):
|
||||
texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False)
|
||||
|
||||
class dvips(Task.Task):
|
||||
run_str = '${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}'
|
||||
color = 'BLUE'
|
||||
after = ['latex', 'pdflatex', 'xelatex']
|
||||
|
||||
class dvipdf(Task.Task):
|
||||
run_str = '${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}'
|
||||
color = 'BLUE'
|
||||
after = ['latex', 'pdflatex', 'xelatex']
|
||||
|
||||
class pdf2ps(Task.Task):
|
||||
run_str = '${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}'
|
||||
color = 'BLUE'
|
||||
after = ['latex', 'pdflatex', 'xelatex']
|
||||
|
||||
@feature('tex')
|
||||
@before_method('process_source')
|
||||
def apply_tex(self):
|
||||
"""
|
||||
Create :py:class:`waflib.Tools.tex.tex` objects, and dvips/dvipdf/pdf2ps tasks if necessary (outs='ps', etc).
|
||||
"""
|
||||
if not getattr(self, 'type', None) in ['latex', 'pdflatex', 'xelatex']:
|
||||
self.type = 'pdflatex'
|
||||
|
||||
tree = self.bld
|
||||
outs = Utils.to_list(getattr(self, 'outs', []))
|
||||
|
||||
# prompt for incomplete files (else the batchmode is used)
|
||||
self.env['PROMPT_LATEX'] = getattr(self, 'prompt', 1)
|
||||
|
||||
deps_lst = []
|
||||
|
||||
if getattr(self, 'deps', None):
|
||||
deps = self.to_list(self.deps)
|
||||
for filename in deps:
|
||||
n = self.path.find_resource(filename)
|
||||
if not n:
|
||||
self.bld.fatal('Could not find %r for %r' % (filename, self))
|
||||
if not n in deps_lst:
|
||||
deps_lst.append(n)
|
||||
|
||||
for node in self.to_nodes(self.source):
|
||||
|
||||
if self.type == 'latex':
|
||||
task = self.create_task('latex', node, node.change_ext('.dvi'))
|
||||
elif self.type == 'pdflatex':
|
||||
task = self.create_task('pdflatex', node, node.change_ext('.pdf'))
|
||||
elif self.type == 'xelatex':
|
||||
task = self.create_task('xelatex', node, node.change_ext('.pdf'))
|
||||
|
||||
task.env = self.env
|
||||
|
||||
# add the manual dependencies
|
||||
if deps_lst:
|
||||
try:
|
||||
lst = tree.node_deps[task.uid()]
|
||||
for n in deps_lst:
|
||||
if not n in lst:
|
||||
lst.append(n)
|
||||
except KeyError:
|
||||
tree.node_deps[task.uid()] = deps_lst
|
||||
|
||||
v = dict(os.environ)
|
||||
p = node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.get_bld().abspath() + os.pathsep + v.get('TEXINPUTS', '') + os.pathsep
|
||||
v['TEXINPUTS'] = p
|
||||
|
||||
if self.type == 'latex':
|
||||
if 'ps' in outs:
|
||||
tsk = self.create_task('dvips', task.outputs, node.change_ext('.ps'))
|
||||
tsk.env.env = dict(v)
|
||||
if 'pdf' in outs:
|
||||
tsk = self.create_task('dvipdf', task.outputs, node.change_ext('.pdf'))
|
||||
tsk.env.env = dict(v)
|
||||
elif self.type == 'pdflatex':
|
||||
if 'ps' in outs:
|
||||
self.create_task('pdf2ps', task.outputs, node.change_ext('.ps'))
|
||||
self.source = []
|
||||
|
||||
def configure(self):
|
||||
"""
|
||||
Try to find the programs tex, latex and others. Do not raise any error if they
|
||||
are not found.
|
||||
"""
|
||||
v = self.env
|
||||
for p in 'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split():
|
||||
try:
|
||||
self.find_program(p, var=p.upper())
|
||||
except self.errors.ConfigurationError:
|
||||
pass
|
||||
v['DVIPSFLAGS'] = '-Ppdf'
|
||||
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Ali Sabil, 2007
|
||||
# Radosław Szkodziński, 2010
|
||||
|
||||
"""
|
||||
At this point, vala is still unstable, so do not expect
|
||||
this tool to be too stable either (apis, etc)
|
||||
"""
|
||||
|
||||
import os.path, shutil, re
|
||||
from waflib import Context, Task, Utils, Logs, Options, Errors
|
||||
from waflib.TaskGen import extension, taskgen_method
|
||||
from waflib.Configure import conf
|
||||
|
||||
class valac(Task.Task):
|
||||
"""
|
||||
Task to compile vala files.
|
||||
"""
|
||||
#run_str = "${VALAC} ${VALAFLAGS}" # ideally
|
||||
#vars = ['VALAC_VERSION']
|
||||
vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"]
|
||||
ext_out = ['.h']
|
||||
|
||||
def run(self):
|
||||
cmd = [self.env['VALAC']] + self.env['VALAFLAGS']
|
||||
cmd.extend([a.abspath() for a in self.inputs])
|
||||
ret = self.exec_command(cmd, cwd=self.outputs[0].parent.abspath())
|
||||
|
||||
if ret:
|
||||
return ret
|
||||
|
||||
for x in self.outputs:
|
||||
if id(x.parent) != id(self.outputs[0].parent):
|
||||
shutil.move(self.outputs[0].parent.abspath() + os.sep + x.name, x.abspath())
|
||||
|
||||
if self.generator.dump_deps_node:
|
||||
self.generator.dump_deps_node.write('\n'.join(self.generator.packages))
|
||||
|
||||
return ret
|
||||
|
||||
valac = Task.update_outputs(valac) # no decorators for python2 classes
|
||||
|
||||
@taskgen_method
|
||||
def init_vala_task(self):
|
||||
self.profile = getattr(self, 'profile', 'gobject')
|
||||
|
||||
if self.profile == 'gobject':
|
||||
self.uselib = Utils.to_list(getattr(self, 'uselib', []))
|
||||
if not 'GOBJECT' in self.uselib:
|
||||
self.uselib.append('GOBJECT')
|
||||
|
||||
def addflags(flags):
|
||||
self.env.append_value('VALAFLAGS', flags)
|
||||
|
||||
if self.profile:
|
||||
addflags('--profile=%s' % self.profile)
|
||||
|
||||
if hasattr(self, 'threading'):
|
||||
if self.profile == 'gobject':
|
||||
if not 'GTHREAD' in self.uselib:
|
||||
self.uselib.append('GTHREAD')
|
||||
else:
|
||||
#Vala doesn't have threading support for dova nor posix
|
||||
Logs.warn("Profile %s means no threading support" % self.profile)
|
||||
self.threading = False
|
||||
|
||||
if self.threading:
|
||||
addflags('--threading')
|
||||
|
||||
valatask = self.valatask
|
||||
|
||||
self.is_lib = 'cprogram' not in self.features
|
||||
if self.is_lib:
|
||||
addflags('--library=%s' % self.target)
|
||||
|
||||
h_node = self.path.find_or_declare('%s.h' % self.target)
|
||||
valatask.outputs.append(h_node)
|
||||
addflags('--header=%s' % h_node.name)
|
||||
|
||||
valatask.outputs.append(self.path.find_or_declare('%s.vapi' % self.target))
|
||||
|
||||
if getattr(self, 'gir', None):
|
||||
gir_node = self.path.find_or_declare('%s.gir' % self.gir)
|
||||
addflags('--gir=%s' % gir_node.name)
|
||||
valatask.outputs.append(gir_node)
|
||||
|
||||
self.vala_target_glib = getattr(self, 'vala_target_glib', getattr(Options.options, 'vala_target_glib', None))
|
||||
if self.vala_target_glib:
|
||||
addflags('--target-glib=%s' % self.vala_target_glib)
|
||||
|
||||
addflags(['--define=%s' % x for x in getattr(self, 'vala_defines', [])])
|
||||
|
||||
|
||||
packages_private = Utils.to_list(getattr(self, 'packages_private', []))
|
||||
addflags(['--pkg=%s' % x for x in packages_private])
|
||||
|
||||
|
||||
def _get_api_version():
|
||||
api_version = '1.0'
|
||||
if hasattr(Context.g_module, 'API_VERSION'):
|
||||
version = Context.g_module.API_VERSION.split(".")
|
||||
if version[0] == "0":
|
||||
api_version = "0." + version[1]
|
||||
else:
|
||||
api_version = version[0] + ".0"
|
||||
return api_version
|
||||
|
||||
self.includes = Utils.to_list(getattr(self, 'includes', []))
|
||||
self.uselib = self.to_list(getattr(self, 'uselib', []))
|
||||
valatask.install_path = getattr(self, 'install_path', '')
|
||||
|
||||
valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi')
|
||||
valatask.pkg_name = getattr(self, 'pkg_name', self.env['PACKAGE'])
|
||||
valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version()))
|
||||
valatask.install_binding = getattr(self, 'install_binding', True)
|
||||
|
||||
self.packages = packages = Utils.to_list(getattr(self, 'packages', []))
|
||||
self.vapi_dirs = vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))
|
||||
includes = []
|
||||
|
||||
if hasattr(self, 'use'):
|
||||
local_packages = Utils.to_list(self.use)[:] # make sure to have a copy
|
||||
seen = []
|
||||
while len(local_packages) > 0:
|
||||
package = local_packages.pop()
|
||||
if package in seen:
|
||||
continue
|
||||
seen.append(package)
|
||||
|
||||
# check if the package exists
|
||||
try:
|
||||
package_obj = self.bld.get_tgen_by_name(package)
|
||||
except Errors.WafError:
|
||||
continue
|
||||
package_name = package_obj.target
|
||||
package_node = package_obj.path
|
||||
package_dir = package_node.path_from(self.path)
|
||||
|
||||
for task in package_obj.tasks:
|
||||
for output in task.outputs:
|
||||
if output.name == package_name + ".vapi":
|
||||
valatask.set_run_after(task)
|
||||
if package_name not in packages:
|
||||
packages.append(package_name)
|
||||
if package_dir not in vapi_dirs:
|
||||
vapi_dirs.append(package_dir)
|
||||
if package_dir not in includes:
|
||||
includes.append(package_dir)
|
||||
|
||||
if hasattr(package_obj, 'use'):
|
||||
lst = self.to_list(package_obj.use)
|
||||
lst.reverse()
|
||||
local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages
|
||||
|
||||
addflags(['--pkg=%s' % p for p in packages])
|
||||
|
||||
for vapi_dir in vapi_dirs:
|
||||
v_node = self.path.find_dir(vapi_dir)
|
||||
if not v_node:
|
||||
Logs.warn('Unable to locate Vala API directory: %r' % vapi_dir)
|
||||
else:
|
||||
addflags('--vapidir=%s' % v_node.abspath())
|
||||
addflags('--vapidir=%s' % v_node.get_bld().abspath())
|
||||
|
||||
self.dump_deps_node = None
|
||||
if self.is_lib and self.packages:
|
||||
self.dump_deps_node = self.path.find_or_declare('%s.deps' % self.target)
|
||||
valatask.outputs.append(self.dump_deps_node)
|
||||
|
||||
self.includes.append(self.bld.srcnode.abspath())
|
||||
self.includes.append(self.bld.bldnode.abspath())
|
||||
for include in includes:
|
||||
try:
|
||||
self.includes.append(self.path.find_dir(include).abspath())
|
||||
self.includes.append(self.path.find_dir(include).get_bld().abspath())
|
||||
except AttributeError:
|
||||
Logs.warn("Unable to locate include directory: '%s'" % include)
|
||||
|
||||
|
||||
if self.is_lib and valatask.install_binding:
|
||||
headers_list = [o for o in valatask.outputs if o.suffix() == ".h"]
|
||||
try:
|
||||
self.install_vheader.source = headers_list
|
||||
except AttributeError:
|
||||
self.install_vheader = self.bld.install_files(valatask.header_path, headers_list, self.env)
|
||||
|
||||
vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))]
|
||||
try:
|
||||
self.install_vapi.source = vapi_list
|
||||
except AttributeError:
|
||||
self.install_vapi = self.bld.install_files(valatask.vapi_path, vapi_list, self.env)
|
||||
|
||||
gir_list = [o for o in valatask.outputs if o.suffix() == '.gir']
|
||||
try:
|
||||
self.install_gir.source = gir_list
|
||||
except AttributeError:
|
||||
self.install_gir = self.bld.install_files(getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0'), gir_list, self.env)
|
||||
|
||||
@extension('.vala', '.gs')
|
||||
def vala_file(self, node):
|
||||
"""
|
||||
Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node
|
||||
to its inputs. The typical example is::
|
||||
|
||||
def build(bld):
|
||||
bld.program(
|
||||
packages = 'gtk+-2.0',
|
||||
target = 'vala-gtk-example',
|
||||
uselib = 'GTK GLIB',
|
||||
source = 'vala-gtk-example.vala foo.vala',
|
||||
vala_defines = ['DEBUG'] # adds --define=<xyz> values to the command-line
|
||||
|
||||
# the following arguments are for libraries
|
||||
#gir = 'hello-1.0',
|
||||
#gir_path = '/tmp',
|
||||
#vapi_path = '/tmp',
|
||||
#pkg_name = 'hello'
|
||||
# disable installing of gir, vapi and header
|
||||
#install_binding = False
|
||||
|
||||
# profile = 'xyz' # adds --profile=<xyz> to enable profiling
|
||||
# threading = True, # add --threading, except if profile is on or not on 'gobject'
|
||||
# vala_target_glib = 'xyz' # adds --target-glib=<xyz>, can be given through the command-line option --vala-target-glib=<xyz>
|
||||
)
|
||||
|
||||
|
||||
:param node: vala file
|
||||
:type node: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
|
||||
try:
|
||||
valatask = self.valatask
|
||||
except AttributeError:
|
||||
valatask = self.valatask = self.create_task('valac')
|
||||
self.init_vala_task()
|
||||
|
||||
valatask.inputs.append(node)
|
||||
c_node = node.change_ext('.c')
|
||||
valatask.outputs.append(c_node)
|
||||
self.source.append(c_node)
|
||||
|
||||
@conf
|
||||
def find_valac(self, valac_name, min_version):
|
||||
"""
|
||||
Find the valac program, and execute it to store the version
|
||||
number in *conf.env.VALAC_VERSION*
|
||||
|
||||
:param valac_name: program name
|
||||
:type valac_name: string or list of string
|
||||
:param min_version: minimum version acceptable
|
||||
:type min_version: tuple of int
|
||||
"""
|
||||
valac = self.find_program(valac_name, var='VALAC')
|
||||
try:
|
||||
output = self.cmd_and_log(valac + ' --version')
|
||||
except Exception:
|
||||
valac_version = None
|
||||
else:
|
||||
ver = re.search(r'\d+.\d+.\d+', output).group(0).split('.')
|
||||
valac_version = tuple([int(x) for x in ver])
|
||||
|
||||
self.msg('Checking for %s version >= %r' % (valac_name, min_version),
|
||||
valac_version, valac_version and valac_version >= min_version)
|
||||
if valac and valac_version < min_version:
|
||||
self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version))
|
||||
|
||||
self.env['VALAC_VERSION'] = valac_version
|
||||
return valac
|
||||
|
||||
@conf
|
||||
def check_vala(self, min_version=(0,8,0), branch=None):
|
||||
"""
|
||||
Check if vala compiler from a given branch exists of at least a given
|
||||
version.
|
||||
|
||||
:param min_version: minimum version acceptable (0.8.0)
|
||||
:type min_version: tuple
|
||||
:param branch: first part of the version number, in case a snapshot is used (0, 8)
|
||||
:type branch: tuple of int
|
||||
"""
|
||||
if not branch:
|
||||
branch = min_version[:2]
|
||||
try:
|
||||
find_valac(self, 'valac-%d.%d' % (branch[0], branch[1]), min_version)
|
||||
except self.errors.ConfigurationError:
|
||||
find_valac(self, 'valac', min_version)
|
||||
|
||||
@conf
|
||||
def check_vala_deps(self):
|
||||
"""
|
||||
Load the gobject and gthread packages if they are missing.
|
||||
"""
|
||||
if not self.env['HAVE_GOBJECT']:
|
||||
pkg_args = {'package': 'gobject-2.0',
|
||||
'uselib_store': 'GOBJECT',
|
||||
'args': '--cflags --libs'}
|
||||
if getattr(Options.options, 'vala_target_glib', None):
|
||||
pkg_args['atleast_version'] = Options.options.vala_target_glib
|
||||
self.check_cfg(**pkg_args)
|
||||
|
||||
if not self.env['HAVE_GTHREAD']:
|
||||
pkg_args = {'package': 'gthread-2.0',
|
||||
'uselib_store': 'GTHREAD',
|
||||
'args': '--cflags --libs'}
|
||||
if getattr(Options.options, 'vala_target_glib', None):
|
||||
pkg_args['atleast_version'] = Options.options.vala_target_glib
|
||||
self.check_cfg(**pkg_args)
|
||||
|
||||
def configure(self):
|
||||
"""
|
||||
Use the following to enforce minimum vala version::
|
||||
|
||||
def configure(conf):
|
||||
conf.load('vala', funs='')
|
||||
conf.check_vala(min_version=(0,10,0))
|
||||
"""
|
||||
self.load('gnu_dirs')
|
||||
self.check_vala_deps()
|
||||
self.check_vala()
|
||||
self.env.VALAFLAGS = ['-C', '--quiet']
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option
|
||||
"""
|
||||
opt.load('gnu_dirs')
|
||||
valaopts = opt.add_option_group('Vala Compiler Options')
|
||||
valaopts.add_option ('--vala-target-glib', default=None,
|
||||
dest='vala_target_glib', metavar='MAJOR.MINOR',
|
||||
help='Target version of glib for Vala GObject code generation')
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Carlos Rafael Giani, 2006
|
||||
# Thomas Nagy, 2010
|
||||
|
||||
"""
|
||||
Unit testing system for C/C++/D providing test execution:
|
||||
|
||||
* in parallel, by using ``waf -j``
|
||||
* partial (only the tests that have changed) or full (by using ``waf --alltests``)
|
||||
|
||||
The tests are declared by adding the **test** feature to programs::
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx waf_unit_test')
|
||||
def configure(conf):
|
||||
conf.load('compiler_cxx waf_unit_test')
|
||||
def build(bld):
|
||||
bld(features='cxx cxxprogram test', source='main.cpp', target='app')
|
||||
# or
|
||||
bld.program(features='test', source='main2.cpp', target='app2')
|
||||
|
||||
When the build is executed, the program 'test' will be built and executed without arguments.
|
||||
The success/failure is detected by looking at the return code. The status and the standard output/error
|
||||
are stored on the build context.
|
||||
|
||||
The results can be displayed by registering a callback function. Here is how to call
|
||||
the predefined callback::
|
||||
|
||||
def build(bld):
|
||||
bld(features='cxx cxxprogram test', source='main.c', target='app')
|
||||
from waflib.Tools import waf_unit_test
|
||||
bld.add_post_fun(waf_unit_test.summary)
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from waflib.TaskGen import feature, after_method
|
||||
from waflib import Utils, Task, Logs, Options
|
||||
testlock = Utils.threading.Lock()
|
||||
|
||||
@feature('test')
|
||||
@after_method('apply_link')
|
||||
def make_test(self):
|
||||
"""Create the unit test task. There can be only one unit test task by task generator."""
|
||||
if getattr(self, 'link_task', None):
|
||||
self.create_task('utest', self.link_task.outputs)
|
||||
|
||||
class utest(Task.Task):
|
||||
"""
|
||||
Execute a unit test
|
||||
"""
|
||||
color = 'PINK'
|
||||
after = ['vnum', 'inst']
|
||||
vars = []
|
||||
def runnable_status(self):
|
||||
"""
|
||||
Always execute the task if `waf --alltests` was used or no
|
||||
tests if ``waf --notests`` was used
|
||||
"""
|
||||
if getattr(Options.options, 'no_tests', False):
|
||||
return Task.SKIP_ME
|
||||
|
||||
ret = super(utest, self).runnable_status()
|
||||
if ret == Task.SKIP_ME:
|
||||
if getattr(Options.options, 'all_tests', False):
|
||||
return Task.RUN_ME
|
||||
return ret
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Execute the test. The execution is always successful, but the results
|
||||
are stored on ``self.generator.bld.utest_results`` for postprocessing.
|
||||
"""
|
||||
|
||||
filename = self.inputs[0].abspath()
|
||||
self.ut_exec = getattr(self.generator, 'ut_exec', [filename])
|
||||
if getattr(self.generator, 'ut_fun', None):
|
||||
# FIXME waf 1.8 - add a return statement here?
|
||||
self.generator.ut_fun(self)
|
||||
|
||||
try:
|
||||
fu = getattr(self.generator.bld, 'all_test_paths')
|
||||
except AttributeError:
|
||||
# this operation may be performed by at most #maxjobs
|
||||
fu = os.environ.copy()
|
||||
|
||||
lst = []
|
||||
for g in self.generator.bld.groups:
|
||||
for tg in g:
|
||||
if getattr(tg, 'link_task', None):
|
||||
s = tg.link_task.outputs[0].parent.abspath()
|
||||
if s not in lst:
|
||||
lst.append(s)
|
||||
|
||||
def add_path(dct, path, var):
|
||||
dct[var] = os.pathsep.join(Utils.to_list(path) + [os.environ.get(var, '')])
|
||||
|
||||
if Utils.is_win32:
|
||||
add_path(fu, lst, 'PATH')
|
||||
elif Utils.unversioned_sys_platform() == 'darwin':
|
||||
add_path(fu, lst, 'DYLD_LIBRARY_PATH')
|
||||
add_path(fu, lst, 'LD_LIBRARY_PATH')
|
||||
else:
|
||||
add_path(fu, lst, 'LD_LIBRARY_PATH')
|
||||
self.generator.bld.all_test_paths = fu
|
||||
|
||||
|
||||
cwd = getattr(self.generator, 'ut_cwd', '') or self.inputs[0].parent.abspath()
|
||||
|
||||
testcmd = getattr(Options.options, 'testcmd', False)
|
||||
if testcmd:
|
||||
self.ut_exec = (testcmd % self.ut_exec[0]).split(' ')
|
||||
|
||||
proc = Utils.subprocess.Popen(self.ut_exec, cwd=cwd, env=fu, stderr=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
|
||||
tup = (filename, proc.returncode, stdout, stderr)
|
||||
self.generator.utest_result = tup
|
||||
|
||||
testlock.acquire()
|
||||
try:
|
||||
bld = self.generator.bld
|
||||
Logs.debug("ut: %r", tup)
|
||||
try:
|
||||
bld.utest_results.append(tup)
|
||||
except AttributeError:
|
||||
bld.utest_results = [tup]
|
||||
finally:
|
||||
testlock.release()
|
||||
|
||||
def summary(bld):
|
||||
"""
|
||||
Display an execution summary::
|
||||
|
||||
def build(bld):
|
||||
bld(features='cxx cxxprogram test', source='main.c', target='app')
|
||||
from waflib.Tools import waf_unit_test
|
||||
bld.add_post_fun(waf_unit_test.summary)
|
||||
"""
|
||||
lst = getattr(bld, 'utest_results', [])
|
||||
if lst:
|
||||
Logs.pprint('CYAN', 'execution summary')
|
||||
|
||||
total = len(lst)
|
||||
tfail = len([x for x in lst if x[1]])
|
||||
|
||||
Logs.pprint('CYAN', ' tests that pass %d/%d' % (total-tfail, total))
|
||||
for (f, code, out, err) in lst:
|
||||
if not code:
|
||||
Logs.pprint('CYAN', ' %s' % f)
|
||||
|
||||
Logs.pprint('CYAN', ' tests that fail %d/%d' % (tfail, total))
|
||||
for (f, code, out, err) in lst:
|
||||
if code:
|
||||
Logs.pprint('CYAN', ' %s' % f)
|
||||
|
||||
def set_exit_code(bld):
|
||||
"""
|
||||
If any of the tests fail waf will exit with that exit code.
|
||||
This is useful if you have an automated build system which need
|
||||
to report on errors from the tests.
|
||||
You may use it like this:
|
||||
|
||||
def build(bld):
|
||||
bld(features='cxx cxxprogram test', source='main.c', target='app')
|
||||
from waflib.Tools import waf_unit_test
|
||||
bld.add_post_fun(waf_unit_test.set_exit_code)
|
||||
"""
|
||||
lst = getattr(bld, 'utest_results', [])
|
||||
for (f, code, out, err) in lst:
|
||||
if code:
|
||||
msg = []
|
||||
if out:
|
||||
msg.append('stdout:%s%s' % (os.linesep, out.decode('utf-8')))
|
||||
if err:
|
||||
msg.append('stderr:%s%s' % (os.linesep, err.decode('utf-8')))
|
||||
bld.fatal(os.linesep.join(msg))
|
||||
|
||||
|
||||
def options(opt):
|
||||
"""
|
||||
Provide the ``--alltests``, ``--notests`` and ``--testcmd`` command-line options.
|
||||
"""
|
||||
opt.add_option('--notests', action='store_true', default=False, help='Exec no unit tests', dest='no_tests')
|
||||
opt.add_option('--alltests', action='store_true', default=False, help='Exec all unit tests', dest='all_tests')
|
||||
opt.add_option('--testcmd', action='store', default=False,
|
||||
help = 'Run the unit tests using the test-cmd string'
|
||||
' example "--test-cmd="valgrind --error-exitcode=1'
|
||||
' %s" to run under valgrind', dest='testcmd')
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Brant Young, 2007
|
||||
|
||||
"Process *.rc* files for C/C++: X{.rc -> [.res|.rc.o]}"
|
||||
|
||||
import re, traceback
|
||||
from waflib import Task, Logs, Utils
|
||||
from waflib.TaskGen import extension
|
||||
from waflib.Tools import c_preproc
|
||||
|
||||
@extension('.rc')
|
||||
def rc_file(self, node):
|
||||
"""
|
||||
Bind the .rc extension to a winrc task
|
||||
"""
|
||||
obj_ext = '.rc.o'
|
||||
if self.env['WINRC_TGT_F'] == '/fo':
|
||||
obj_ext = '.res'
|
||||
rctask = self.create_task('winrc', node, node.change_ext(obj_ext))
|
||||
try:
|
||||
self.compiled_tasks.append(rctask)
|
||||
except AttributeError:
|
||||
self.compiled_tasks = [rctask]
|
||||
|
||||
re_lines = re.compile(
|
||||
'(?:^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*?)\s*$)|'\
|
||||
'(?:^\w+[ \t]*(ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)[ \t]*(.*?)\s*$)',
|
||||
re.IGNORECASE | re.MULTILINE)
|
||||
|
||||
class rc_parser(c_preproc.c_parser):
|
||||
def filter_comments(self, filepath):
|
||||
code = Utils.readf(filepath)
|
||||
if c_preproc.use_trigraphs:
|
||||
for (a, b) in c_preproc.trig_def: code = code.split(a).join(b)
|
||||
code = c_preproc.re_nl.sub('', code)
|
||||
code = c_preproc.re_cpp.sub(c_preproc.repl, code)
|
||||
ret = []
|
||||
for m in re.finditer(re_lines, code):
|
||||
if m.group(2):
|
||||
ret.append((m.group(2), m.group(3)))
|
||||
else:
|
||||
ret.append(('include', m.group(5)))
|
||||
return ret
|
||||
|
||||
def addlines(self, node):
|
||||
self.currentnode_stack.append(node.parent)
|
||||
filepath = node.abspath()
|
||||
|
||||
self.count_files += 1
|
||||
if self.count_files > c_preproc.recursion_limit:
|
||||
raise c_preproc.PreprocError("recursion limit exceeded")
|
||||
pc = self.parse_cache
|
||||
Logs.debug('preproc: reading file %r', filepath)
|
||||
try:
|
||||
lns = pc[filepath]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
self.lines.extend(lns)
|
||||
return
|
||||
|
||||
try:
|
||||
lines = self.filter_comments(filepath)
|
||||
lines.append((c_preproc.POPFILE, ''))
|
||||
lines.reverse()
|
||||
pc[filepath] = lines
|
||||
self.lines.extend(lines)
|
||||
except IOError:
|
||||
raise c_preproc.PreprocError("could not read the file %s" % filepath)
|
||||
except Exception:
|
||||
if Logs.verbose > 0:
|
||||
Logs.error("parsing %s failed" % filepath)
|
||||
traceback.print_exc()
|
||||
|
||||
class winrc(Task.Task):
|
||||
"""
|
||||
Task for compiling resource files
|
||||
"""
|
||||
run_str = '${WINRC} ${WINRCFLAGS} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${WINRC_TGT_F} ${TGT} ${WINRC_SRC_F} ${SRC}'
|
||||
color = 'BLUE'
|
||||
|
||||
def scan(self):
|
||||
tmp = rc_parser(self.generator.includes_nodes)
|
||||
tmp.start(self.inputs[0], self.env)
|
||||
nodes = tmp.nodes
|
||||
names = tmp.names
|
||||
|
||||
if Logs.verbose:
|
||||
Logs.debug('deps: deps for %s: %r; unresolved %r' % (str(self), nodes, names))
|
||||
|
||||
return (nodes, names)
|
||||
|
||||
def configure(conf):
|
||||
"""
|
||||
Detect the programs RC or windres, depending on the C/C++ compiler in use
|
||||
"""
|
||||
v = conf.env
|
||||
v['WINRC_TGT_F'] = '-o'
|
||||
v['WINRC_SRC_F'] = '-i'
|
||||
|
||||
# find rc.exe
|
||||
if not conf.env.WINRC:
|
||||
if v.CC_NAME == 'msvc':
|
||||
conf.find_program('RC', var='WINRC', path_list = v['PATH'])
|
||||
v['WINRC_TGT_F'] = '/fo'
|
||||
v['WINRC_SRC_F'] = ''
|
||||
else:
|
||||
conf.find_program('windres', var='WINRC', path_list = v['PATH'])
|
||||
if not conf.env.WINRC:
|
||||
conf.fatal('winrc was not found!')
|
||||
|
||||
v['WINRCFLAGS'] = []
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
# Yinon Ehrlich, 2009
|
||||
# Michael Kuhn, 2009
|
||||
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_xlc(conf):
|
||||
"""
|
||||
Detect the Aix C compiler
|
||||
"""
|
||||
cc = conf.find_program(['xlc_r', 'xlc'], var='CC')
|
||||
cc = conf.cmd_to_list(cc)
|
||||
conf.get_xlc_version(cc)
|
||||
conf.env.CC_NAME = 'xlc'
|
||||
conf.env.CC = cc
|
||||
|
||||
@conf
|
||||
def xlc_common_flags(conf):
|
||||
"""
|
||||
Flags required for executing the Aix C compiler
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['CC_SRC_F'] = []
|
||||
v['CC_TGT_F'] = ['-c', '-o']
|
||||
|
||||
# linker
|
||||
if not v['LINK_CC']: v['LINK_CC'] = v['CC']
|
||||
v['CCLNK_SRC_F'] = []
|
||||
v['CCLNK_TGT_F'] = ['-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
v['RPATH_ST'] = '-Wl,-rpath,%s'
|
||||
|
||||
v['SONAME_ST'] = []
|
||||
v['SHLIB_MARKER'] = []
|
||||
v['STLIB_MARKER'] = []
|
||||
|
||||
# program
|
||||
v['LINKFLAGS_cprogram'] = ['-Wl,-brtl']
|
||||
v['cprogram_PATTERN'] = '%s'
|
||||
|
||||
# shared library
|
||||
v['CFLAGS_cshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_cshlib'] = ['-G', '-Wl,-brtl,-bexpfull']
|
||||
v['cshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
# static lib
|
||||
v['LINKFLAGS_cstlib'] = []
|
||||
v['cstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_xlc()
|
||||
conf.find_ar()
|
||||
conf.xlc_common_flags()
|
||||
conf.cc_load_tools()
|
||||
conf.cc_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2006-2010 (ita)
|
||||
# Ralf Habacker, 2006 (rh)
|
||||
# Yinon Ehrlich, 2009
|
||||
# Michael Kuhn, 2009
|
||||
|
||||
from waflib.Tools import ccroot, ar
|
||||
from waflib.Configure import conf
|
||||
|
||||
@conf
|
||||
def find_xlcxx(conf):
|
||||
"""
|
||||
Detect the Aix C++ compiler
|
||||
"""
|
||||
cxx = conf.find_program(['xlc++_r', 'xlc++'], var='CXX')
|
||||
cxx = conf.cmd_to_list(cxx)
|
||||
conf.get_xlc_version(cxx)
|
||||
conf.env.CXX_NAME = 'xlc++'
|
||||
conf.env.CXX = cxx
|
||||
|
||||
@conf
|
||||
def xlcxx_common_flags(conf):
|
||||
"""
|
||||
Flags required for executing the Aix C++ compiler
|
||||
"""
|
||||
v = conf.env
|
||||
|
||||
v['CXX_SRC_F'] = []
|
||||
v['CXX_TGT_F'] = ['-c', '-o']
|
||||
|
||||
# linker
|
||||
if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']
|
||||
v['CXXLNK_SRC_F'] = []
|
||||
v['CXXLNK_TGT_F'] = ['-o']
|
||||
v['CPPPATH_ST'] = '-I%s'
|
||||
v['DEFINES_ST'] = '-D%s'
|
||||
|
||||
v['LIB_ST'] = '-l%s' # template for adding libs
|
||||
v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
|
||||
v['STLIB_ST'] = '-l%s'
|
||||
v['STLIBPATH_ST'] = '-L%s'
|
||||
v['RPATH_ST'] = '-Wl,-rpath,%s'
|
||||
|
||||
v['SONAME_ST'] = []
|
||||
v['SHLIB_MARKER'] = []
|
||||
v['STLIB_MARKER'] = []
|
||||
|
||||
# program
|
||||
v['LINKFLAGS_cxxprogram']= ['-Wl,-brtl']
|
||||
v['cxxprogram_PATTERN'] = '%s'
|
||||
|
||||
# shared library
|
||||
v['CXXFLAGS_cxxshlib'] = ['-fPIC']
|
||||
v['LINKFLAGS_cxxshlib'] = ['-G', '-Wl,-brtl,-bexpfull']
|
||||
v['cxxshlib_PATTERN'] = 'lib%s.so'
|
||||
|
||||
# static lib
|
||||
v['LINKFLAGS_cxxstlib'] = []
|
||||
v['cxxstlib_PATTERN'] = 'lib%s.a'
|
||||
|
||||
def configure(conf):
|
||||
conf.find_xlcxx()
|
||||
conf.find_ar()
|
||||
conf.xlcxx_common_flags()
|
||||
conf.cxx_load_tools()
|
||||
conf.cxx_add_flags()
|
||||
conf.link_add_flags()
|
||||
|
||||
+709
@@ -0,0 +1,709 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
|
||||
"""
|
||||
Utilities and platform-specific fixes
|
||||
|
||||
The portability fixes try to provide a consistent behavior of the Waf API
|
||||
through Python versions 2.3 to 3.X and across different platforms (win32, linux, etc)
|
||||
"""
|
||||
|
||||
import os, sys, errno, traceback, inspect, re, shutil, datetime, gc
|
||||
import subprocess # <- leave this!
|
||||
|
||||
try:
|
||||
from collections import deque
|
||||
except ImportError:
|
||||
class deque(list):
|
||||
"""A deque for Python 2.3 which does not have one"""
|
||||
def popleft(self):
|
||||
return self.pop(0)
|
||||
try:
|
||||
import _winreg as winreg
|
||||
except ImportError:
|
||||
try:
|
||||
import winreg
|
||||
except ImportError:
|
||||
winreg = None
|
||||
|
||||
from waflib import Errors
|
||||
|
||||
try:
|
||||
from collections import UserDict
|
||||
except ImportError:
|
||||
from UserDict import UserDict
|
||||
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
try:
|
||||
from md5 import md5
|
||||
except ImportError:
|
||||
# never fail to enable fixes from another module
|
||||
pass
|
||||
|
||||
try:
|
||||
import threading
|
||||
except ImportError:
|
||||
class threading(object):
|
||||
"""
|
||||
A fake threading class for platforms lacking the threading module.
|
||||
Use ``waf -j1`` on those platforms
|
||||
"""
|
||||
pass
|
||||
class Lock(object):
|
||||
"""Fake Lock class"""
|
||||
def acquire(self):
|
||||
pass
|
||||
def release(self):
|
||||
pass
|
||||
threading.Lock = threading.Thread = Lock
|
||||
else:
|
||||
run_old = threading.Thread.run
|
||||
def run(*args, **kwargs):
|
||||
try:
|
||||
run_old(*args, **kwargs)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
sys.excepthook(*sys.exc_info())
|
||||
threading.Thread.run = run
|
||||
|
||||
SIG_NIL = 'iluvcuteoverload'.encode()
|
||||
"""Arbitrary null value for a md5 hash. This value must be changed when the hash value is replaced (size)"""
|
||||
|
||||
O644 = 420
|
||||
"""Constant representing the permissions for regular files (0644 raises a syntax error on python 3)"""
|
||||
|
||||
O755 = 493
|
||||
"""Constant representing the permissions for executable files (0755 raises a syntax error on python 3)"""
|
||||
|
||||
rot_chr = ['\\', '|', '/', '-']
|
||||
"List of characters to use when displaying the throbber (progress bar)"
|
||||
|
||||
rot_idx = 0
|
||||
"Index of the current throbber character (progress bar)"
|
||||
|
||||
try:
|
||||
from collections import defaultdict
|
||||
except ImportError:
|
||||
class defaultdict(dict):
|
||||
"""
|
||||
defaultdict was introduced in python 2.5, so we leave it for python 2.4 and 2.3
|
||||
"""
|
||||
def __init__(self, default_factory):
|
||||
super(defaultdict, self).__init__()
|
||||
self.default_factory = default_factory
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return super(defaultdict, self).__getitem__(key)
|
||||
except KeyError:
|
||||
value = self.default_factory()
|
||||
self[key] = value
|
||||
return value
|
||||
|
||||
is_win32 = sys.platform in ('win32', 'cli')
|
||||
|
||||
# we should have put this in the Logs.py file instead :-/
|
||||
indicator = '\x1b[K%s%s%s\r'
|
||||
if is_win32 and 'NOCOLOR' in os.environ:
|
||||
indicator = '%s%s%s\r'
|
||||
|
||||
def readf(fname, m='r', encoding='ISO8859-1'):
|
||||
"""
|
||||
Read an entire file into a string, use this function instead of os.open() whenever possible.
|
||||
|
||||
In practice the wrapper node.read(..) should be preferred to this function::
|
||||
|
||||
def build(ctx):
|
||||
from waflib import Utils
|
||||
txt = Utils.readf(self.path.find_node('wscript').abspath())
|
||||
txt = ctx.path.find_node('wscript').read()
|
||||
|
||||
:type fname: string
|
||||
:param fname: Path to file
|
||||
:type m: string
|
||||
:param m: Open mode
|
||||
:type encoding: string
|
||||
:param encoding: encoding value, only used for python 3
|
||||
:rtype: string
|
||||
:return: Content of the file
|
||||
"""
|
||||
|
||||
if sys.hexversion > 0x3000000 and not 'b' in m:
|
||||
m += 'b'
|
||||
f = open(fname, m)
|
||||
try:
|
||||
txt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
txt = txt.decode(encoding)
|
||||
else:
|
||||
f = open(fname, m)
|
||||
try:
|
||||
txt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
return txt
|
||||
|
||||
def writef(fname, data, m='w', encoding='ISO8859-1'):
|
||||
"""
|
||||
Write an entire file from a string, use this function instead of os.open() whenever possible.
|
||||
|
||||
In practice the wrapper node.write(..) should be preferred to this function::
|
||||
|
||||
def build(ctx):
|
||||
from waflib import Utils
|
||||
txt = Utils.writef(self.path.make_node('i_like_kittens').abspath(), 'some data')
|
||||
self.path.make_node('i_like_kittens').write('some data')
|
||||
|
||||
:type fname: string
|
||||
:param fname: Path to file
|
||||
:type data: string
|
||||
:param data: The contents to write to the file
|
||||
:type m: string
|
||||
:param m: Open mode
|
||||
:type encoding: string
|
||||
:param encoding: encoding value, only used for python 3
|
||||
"""
|
||||
if sys.hexversion > 0x3000000 and not 'b' in m:
|
||||
data = data.encode(encoding)
|
||||
m += 'b'
|
||||
f = open(fname, m)
|
||||
try:
|
||||
f.write(data)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def h_file(fname):
|
||||
"""
|
||||
Compute a hash value for a file by using md5. This method may be replaced by
|
||||
a faster version if necessary. The following uses the file size and the timestamp value::
|
||||
|
||||
import stat
|
||||
from waflib import Utils
|
||||
def h_file(fname):
|
||||
st = os.stat(fname)
|
||||
if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
|
||||
m = Utils.md5()
|
||||
m.update(str(st.st_mtime))
|
||||
m.update(str(st.st_size))
|
||||
m.update(fname)
|
||||
return m.digest()
|
||||
Utils.h_file = h_file
|
||||
|
||||
:type fname: string
|
||||
:param fname: path to the file to hash
|
||||
:return: hash of the file contents
|
||||
"""
|
||||
f = open(fname, 'rb')
|
||||
m = md5()
|
||||
try:
|
||||
while fname:
|
||||
fname = f.read(200000)
|
||||
m.update(fname)
|
||||
finally:
|
||||
f.close()
|
||||
return m.digest()
|
||||
|
||||
if hasattr(os, 'O_NOINHERIT'):
|
||||
def readf_win32(f, m='r', encoding='ISO8859-1'):
|
||||
flags = os.O_NOINHERIT | os.O_RDONLY
|
||||
if 'b' in m:
|
||||
flags |= os.O_BINARY
|
||||
if '+' in m:
|
||||
flags |= os.O_RDWR
|
||||
try:
|
||||
fd = os.open(f, flags)
|
||||
except OSError:
|
||||
raise IOError('Cannot read from %r' % f)
|
||||
|
||||
if sys.hexversion > 0x3000000 and not 'b' in m:
|
||||
m += 'b'
|
||||
f = os.fdopen(fd, m)
|
||||
try:
|
||||
txt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
txt = txt.decode(encoding)
|
||||
else:
|
||||
f = os.fdopen(fd, m)
|
||||
try:
|
||||
txt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
return txt
|
||||
|
||||
def writef_win32(f, data, m='w', encoding='ISO8859-1'):
|
||||
if sys.hexversion > 0x3000000 and not 'b' in m:
|
||||
data = data.encode(encoding)
|
||||
m += 'b'
|
||||
flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT
|
||||
if 'b' in m:
|
||||
flags |= os.O_BINARY
|
||||
if '+' in m:
|
||||
flags |= os.O_RDWR
|
||||
try:
|
||||
fd = os.open(f, flags)
|
||||
except OSError:
|
||||
raise IOError('Cannot write to %r' % f)
|
||||
f = os.fdopen(fd, m)
|
||||
try:
|
||||
f.write(data)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def h_file_win32(fname):
|
||||
try:
|
||||
fd = os.open(fname, os.O_BINARY | os.O_RDONLY | os.O_NOINHERIT)
|
||||
except OSError:
|
||||
raise IOError('Cannot read from %r' % fname)
|
||||
f = os.fdopen(fd, 'rb')
|
||||
m = md5()
|
||||
try:
|
||||
while fname:
|
||||
fname = f.read(200000)
|
||||
m.update(fname)
|
||||
finally:
|
||||
f.close()
|
||||
return m.digest()
|
||||
|
||||
# replace the default functions
|
||||
readf_old = readf
|
||||
writef_old = writef
|
||||
h_file_old = h_file
|
||||
readf = readf_win32
|
||||
writef = writef_win32
|
||||
h_file = h_file_win32
|
||||
|
||||
try:
|
||||
x = ''.encode('hex')
|
||||
except LookupError:
|
||||
import binascii
|
||||
def to_hex(s):
|
||||
ret = binascii.hexlify(s)
|
||||
if not isinstance(ret, str):
|
||||
ret = ret.decode('utf-8')
|
||||
return ret
|
||||
else:
|
||||
def to_hex(s):
|
||||
return s.encode('hex')
|
||||
|
||||
to_hex.__doc__ = """
|
||||
Return the hexadecimal representation of a string
|
||||
|
||||
:param s: string to convert
|
||||
:type s: string
|
||||
"""
|
||||
|
||||
listdir = os.listdir
|
||||
if is_win32:
|
||||
def listdir_win32(s):
|
||||
"""
|
||||
List the contents of a folder in a portable manner.
|
||||
On Win32, return the list of drive letters: ['C:', 'X:', 'Z:']
|
||||
|
||||
:type s: string
|
||||
:param s: a string, which can be empty on Windows
|
||||
"""
|
||||
if not s:
|
||||
try:
|
||||
import ctypes
|
||||
except ImportError:
|
||||
# there is nothing much we can do
|
||||
return [x + ':\\' for x in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')]
|
||||
else:
|
||||
dlen = 4 # length of "?:\\x00"
|
||||
maxdrives = 26
|
||||
buf = ctypes.create_string_buffer(maxdrives * dlen)
|
||||
ndrives = ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen, ctypes.byref(buf))
|
||||
return [ str(buf.raw[4*i:4*i+2].decode('ascii')) for i in range(int(ndrives/dlen)) ]
|
||||
|
||||
if len(s) == 2 and s[1] == ":":
|
||||
s += os.sep
|
||||
|
||||
if not os.path.isdir(s):
|
||||
e = OSError('%s is not a directory' % s)
|
||||
e.errno = errno.ENOENT
|
||||
raise e
|
||||
return os.listdir(s)
|
||||
listdir = listdir_win32
|
||||
|
||||
def num2ver(ver):
|
||||
"""
|
||||
Convert a string, tuple or version number into an integer. The number is supposed to have at most 4 digits::
|
||||
|
||||
from waflib.Utils import num2ver
|
||||
num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))
|
||||
|
||||
:type ver: string or tuple of numbers
|
||||
:param ver: a version number
|
||||
"""
|
||||
if isinstance(ver, str):
|
||||
ver = tuple(ver.split('.'))
|
||||
if isinstance(ver, tuple):
|
||||
ret = 0
|
||||
for i in range(4):
|
||||
if i < len(ver):
|
||||
ret += 256**(3 - i) * int(ver[i])
|
||||
return ret
|
||||
return ver
|
||||
|
||||
def ex_stack():
|
||||
"""
|
||||
Extract the stack to display exceptions
|
||||
|
||||
:return: a string represening the last exception
|
||||
"""
|
||||
exc_type, exc_value, tb = sys.exc_info()
|
||||
exc_lines = traceback.format_exception(exc_type, exc_value, tb)
|
||||
return ''.join(exc_lines)
|
||||
|
||||
def to_list(sth):
|
||||
"""
|
||||
Convert a string argument to a list by splitting on spaces, and pass
|
||||
through a list argument unchanged::
|
||||
|
||||
from waflib.Utils import to_list
|
||||
lst = to_list("a b c d")
|
||||
|
||||
:param sth: List or a string of items separated by spaces
|
||||
:rtype: list
|
||||
:return: Argument converted to list
|
||||
|
||||
"""
|
||||
if isinstance(sth, str):
|
||||
return sth.split()
|
||||
else:
|
||||
return sth
|
||||
|
||||
re_nl = re.compile('\r*\n', re.M)
|
||||
def str_to_dict(txt):
|
||||
"""
|
||||
Parse a string with key = value pairs into a dictionary::
|
||||
|
||||
from waflib import Utils
|
||||
x = Utils.str_to_dict('''
|
||||
a = 1
|
||||
b = test
|
||||
''')
|
||||
|
||||
:type s: string
|
||||
:param s: String to parse
|
||||
:rtype: dict
|
||||
:return: Dictionary containing parsed key-value pairs
|
||||
"""
|
||||
tbl = {}
|
||||
|
||||
lines = re_nl.split(txt)
|
||||
for x in lines:
|
||||
x = x.strip()
|
||||
if not x or x.startswith('#') or x.find('=') < 0:
|
||||
continue
|
||||
tmp = x.split('=')
|
||||
tbl[tmp[0].strip()] = '='.join(tmp[1:]).strip()
|
||||
return tbl
|
||||
|
||||
def split_path(path):
|
||||
return path.split('/')
|
||||
|
||||
def split_path_cygwin(path):
|
||||
if path.startswith('//'):
|
||||
ret = path.split('/')[2:]
|
||||
ret[0] = '/' + ret[0]
|
||||
return ret
|
||||
return path.split('/')
|
||||
|
||||
re_sp = re.compile('[/\\\\]')
|
||||
def split_path_win32(path):
|
||||
if path.startswith('\\\\'):
|
||||
ret = re.split(re_sp, path)[2:]
|
||||
ret[0] = '\\' + ret[0]
|
||||
return ret
|
||||
return re.split(re_sp, path)
|
||||
|
||||
if sys.platform == 'cygwin':
|
||||
split_path = split_path_cygwin
|
||||
elif is_win32:
|
||||
split_path = split_path_win32
|
||||
|
||||
split_path.__doc__ = """
|
||||
Split a path by / or \\. This function is not like os.path.split
|
||||
|
||||
:type path: string
|
||||
:param path: path to split
|
||||
:return: list of strings
|
||||
"""
|
||||
|
||||
def check_dir(path):
|
||||
"""
|
||||
Ensure that a directory exists (similar to ``mkdir -p``).
|
||||
|
||||
:type dir: string
|
||||
:param dir: Path to directory
|
||||
"""
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as e:
|
||||
if not os.path.isdir(path):
|
||||
raise Errors.WafError('Cannot create the folder %r' % path, ex=e)
|
||||
|
||||
def def_attrs(cls, **kw):
|
||||
"""
|
||||
Set default attributes on a class instance
|
||||
|
||||
:type cls: class
|
||||
:param cls: the class to update the given attributes in.
|
||||
:type kw: dict
|
||||
:param kw: dictionary of attributes names and values.
|
||||
"""
|
||||
for k, v in kw.items():
|
||||
if not hasattr(cls, k):
|
||||
setattr(cls, k, v)
|
||||
|
||||
def quote_define_name(s):
|
||||
"""
|
||||
Convert a string to an identifier suitable for C defines.
|
||||
|
||||
:type s: string
|
||||
:param s: String to convert
|
||||
:rtype: string
|
||||
:return: Identifier suitable for C defines
|
||||
"""
|
||||
fu = re.compile("[^a-zA-Z0-9]").sub("_", s)
|
||||
fu = fu.upper()
|
||||
return fu
|
||||
|
||||
def h_list(lst):
|
||||
"""
|
||||
Hash lists. For tuples, using hash(tup) is much more efficient
|
||||
|
||||
:param lst: list to hash
|
||||
:type lst: list of strings
|
||||
:return: hash of the list
|
||||
"""
|
||||
m = md5()
|
||||
m.update(str(lst).encode())
|
||||
return m.digest()
|
||||
|
||||
def h_fun(fun):
|
||||
"""
|
||||
Hash functions
|
||||
|
||||
:param fun: function to hash
|
||||
:type fun: function
|
||||
:return: hash of the function
|
||||
"""
|
||||
try:
|
||||
return fun.code
|
||||
except AttributeError:
|
||||
try:
|
||||
h = inspect.getsource(fun)
|
||||
except IOError:
|
||||
h = "nocode"
|
||||
try:
|
||||
fun.code = h
|
||||
except AttributeError:
|
||||
pass
|
||||
return h
|
||||
|
||||
reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
|
||||
def subst_vars(expr, params):
|
||||
"""
|
||||
Replace ${VAR} with the value of VAR taken from a dict or a config set::
|
||||
|
||||
from waflib import Utils
|
||||
s = Utils.subst_vars('${PREFIX}/bin', env)
|
||||
|
||||
:type expr: string
|
||||
:param expr: String to perform substitution on
|
||||
:param params: Dictionary or config set to look up variable values.
|
||||
"""
|
||||
def repl_var(m):
|
||||
if m.group(1):
|
||||
return '\\'
|
||||
if m.group(2):
|
||||
return '$'
|
||||
try:
|
||||
# ConfigSet instances may contain lists
|
||||
return params.get_flat(m.group(3))
|
||||
except AttributeError:
|
||||
return params[m.group(3)]
|
||||
return reg_subst.sub(repl_var, expr)
|
||||
|
||||
def destos_to_binfmt(key):
|
||||
"""
|
||||
Return the binary format based on the unversioned platform name.
|
||||
|
||||
:param key: platform name
|
||||
:type key: string
|
||||
:return: string representing the binary format
|
||||
"""
|
||||
if key == 'darwin':
|
||||
return 'mac-o'
|
||||
elif key in ('win32', 'cygwin', 'uwin', 'msys'):
|
||||
return 'pe'
|
||||
return 'elf'
|
||||
|
||||
def unversioned_sys_platform():
|
||||
"""
|
||||
Return the unversioned platform name.
|
||||
Some Python platform names contain versions, that depend on
|
||||
the build environment, e.g. linux2, freebsd6, etc.
|
||||
This returns the name without the version number. Exceptions are
|
||||
os2 and win32, which are returned verbatim.
|
||||
|
||||
:rtype: string
|
||||
:return: Unversioned platform name
|
||||
"""
|
||||
s = sys.platform
|
||||
if s == 'java':
|
||||
# The real OS is hidden under the JVM.
|
||||
from java.lang import System
|
||||
s = System.getProperty('os.name')
|
||||
# see http://lopica.sourceforge.net/os.html for a list of possible values
|
||||
if s == 'Mac OS X':
|
||||
return 'darwin'
|
||||
elif s.startswith('Windows '):
|
||||
return 'win32'
|
||||
elif s == 'OS/2':
|
||||
return 'os2'
|
||||
elif s == 'HP-UX':
|
||||
return 'hpux'
|
||||
elif s in ('SunOS', 'Solaris'):
|
||||
return 'sunos'
|
||||
else: s = s.lower()
|
||||
|
||||
# powerpc == darwin for our purposes
|
||||
if s == 'powerpc':
|
||||
return 'darwin'
|
||||
if s == 'win32' or s.endswith('os2') and s != 'sunos2': return s
|
||||
return re.split('\d+$', s)[0]
|
||||
|
||||
def nada(*k, **kw):
|
||||
"""
|
||||
A function that does nothing
|
||||
|
||||
:return: None
|
||||
"""
|
||||
pass
|
||||
|
||||
class Timer(object):
|
||||
"""
|
||||
Simple object for timing the execution of commands.
|
||||
Its string representation is the current time::
|
||||
|
||||
from waflib.Utils import Timer
|
||||
timer = Timer()
|
||||
a_few_operations()
|
||||
s = str(timer)
|
||||
"""
|
||||
def __init__(self):
|
||||
self.start_time = datetime.datetime.utcnow()
|
||||
|
||||
def __str__(self):
|
||||
delta = datetime.datetime.utcnow() - self.start_time
|
||||
days = int(delta.days)
|
||||
hours = delta.seconds // 3600
|
||||
minutes = (delta.seconds - hours * 3600) // 60
|
||||
seconds = delta.seconds - hours * 3600 - minutes * 60 + float(delta.microseconds) / 1000 / 1000
|
||||
result = ''
|
||||
if days:
|
||||
result += '%dd' % days
|
||||
if days or hours:
|
||||
result += '%dh' % hours
|
||||
if days or hours or minutes:
|
||||
result += '%dm' % minutes
|
||||
return '%s%.3fs' % (result, seconds)
|
||||
|
||||
if is_win32:
|
||||
old = shutil.copy2
|
||||
def copy2(src, dst):
|
||||
"""
|
||||
shutil.copy2 does not copy the file attributes on windows, so we
|
||||
hack into the shutil module to fix the problem
|
||||
"""
|
||||
old(src, dst)
|
||||
shutil.copystat(src, dst)
|
||||
setattr(shutil, 'copy2', copy2)
|
||||
|
||||
if os.name == 'java':
|
||||
# Jython cannot disable the gc but they can enable it ... wtf?
|
||||
try:
|
||||
gc.disable()
|
||||
gc.enable()
|
||||
except NotImplementedError:
|
||||
gc.disable = gc.enable
|
||||
|
||||
def read_la_file(path):
|
||||
"""
|
||||
Read property files, used by msvc.py
|
||||
|
||||
:param path: file to read
|
||||
:type path: string
|
||||
"""
|
||||
sp = re.compile(r'^([^=]+)=\'(.*)\'$')
|
||||
dc = {}
|
||||
for line in readf(path).splitlines():
|
||||
try:
|
||||
_, left, right, _ = sp.split(line.strip())
|
||||
dc[left] = right
|
||||
except ValueError:
|
||||
pass
|
||||
return dc
|
||||
|
||||
def nogc(fun):
|
||||
"""
|
||||
Decorator: let a function disable the garbage collector during its execution.
|
||||
It is used in the build context when storing/loading the build cache file (pickle)
|
||||
|
||||
:param fun: function to execute
|
||||
:type fun: function
|
||||
:return: the return value of the function executed
|
||||
"""
|
||||
def f(*k, **kw):
|
||||
try:
|
||||
gc.disable()
|
||||
ret = fun(*k, **kw)
|
||||
finally:
|
||||
gc.enable()
|
||||
return ret
|
||||
f.__doc__ = fun.__doc__
|
||||
return f
|
||||
|
||||
def run_once(fun):
|
||||
"""
|
||||
Decorator: let a function cache its results, use like this::
|
||||
|
||||
@run_once
|
||||
def foo(k):
|
||||
return 345*2343
|
||||
|
||||
:param fun: function to execute
|
||||
:type fun: function
|
||||
:return: the return value of the function executed
|
||||
"""
|
||||
cache = {}
|
||||
def wrap(k):
|
||||
try:
|
||||
return cache[k]
|
||||
except KeyError:
|
||||
ret = fun(k)
|
||||
cache[k] = ret
|
||||
return ret
|
||||
wrap.__cache__ = cache
|
||||
return wrap
|
||||
|
||||
def get_registry_app_path(key, filename):
|
||||
if not winreg:
|
||||
return None
|
||||
try:
|
||||
result = winreg.QueryValue(key, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe" % filename[0])
|
||||
except WindowsError:
|
||||
pass
|
||||
else:
|
||||
if os.path.isfile(result):
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010 (ita)
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
import sys, os
|
||||
try:
|
||||
if not (sys.stderr.isatty() and sys.stdout.isatty()):
|
||||
raise ValueError('not a tty')
|
||||
|
||||
from ctypes import *
|
||||
|
||||
class COORD(Structure):
|
||||
_fields_ = [("X", c_short), ("Y", c_short)]
|
||||
|
||||
class SMALL_RECT(Structure):
|
||||
_fields_ = [("Left", c_short), ("Top", c_short), ("Right", c_short), ("Bottom", c_short)]
|
||||
|
||||
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
|
||||
_fields_ = [("Size", COORD), ("CursorPosition", COORD), ("Attributes", c_short), ("Window", SMALL_RECT), ("MaximumWindowSize", COORD)]
|
||||
|
||||
class CONSOLE_CURSOR_INFO(Structure):
|
||||
_fields_ = [('dwSize',c_ulong), ('bVisible', c_int)]
|
||||
|
||||
sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
|
||||
csinfo = CONSOLE_CURSOR_INFO()
|
||||
hconsole = windll.kernel32.GetStdHandle(-11)
|
||||
windll.kernel32.GetConsoleScreenBufferInfo(hconsole, byref(sbinfo))
|
||||
if sbinfo.Size.X < 9 or sbinfo.Size.Y < 9: raise ValueError('small console')
|
||||
windll.kernel32.GetConsoleCursorInfo(hconsole, byref(csinfo))
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
import re, threading
|
||||
|
||||
is_vista = getattr(sys, "getwindowsversion", None) and sys.getwindowsversion()[0] >= 6
|
||||
|
||||
try:
|
||||
_type = unicode
|
||||
except NameError:
|
||||
_type = str
|
||||
|
||||
to_int = lambda number, default: number and int(number) or default
|
||||
wlock = threading.Lock()
|
||||
|
||||
STD_OUTPUT_HANDLE = -11
|
||||
STD_ERROR_HANDLE = -12
|
||||
|
||||
class AnsiTerm(object):
|
||||
"""
|
||||
emulate a vt100 terminal in cmd.exe
|
||||
"""
|
||||
def __init__(self):
|
||||
self.encoding = sys.stdout.encoding
|
||||
self.hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
self.cursor_history = []
|
||||
self.orig_sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
|
||||
self.orig_csinfo = CONSOLE_CURSOR_INFO()
|
||||
windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(self.orig_sbinfo))
|
||||
windll.kernel32.GetConsoleCursorInfo(hconsole, byref(self.orig_csinfo))
|
||||
|
||||
def screen_buffer_info(self):
|
||||
sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
|
||||
windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))
|
||||
return sbinfo
|
||||
|
||||
def clear_line(self, param):
|
||||
mode = param and int(param) or 0
|
||||
sbinfo = self.screen_buffer_info()
|
||||
if mode == 1: # Clear from begining of line to cursor position
|
||||
line_start = COORD(0, sbinfo.CursorPosition.Y)
|
||||
line_length = sbinfo.Size.X
|
||||
elif mode == 2: # Clear entire line
|
||||
line_start = COORD(sbinfo.CursorPosition.X, sbinfo.CursorPosition.Y)
|
||||
line_length = sbinfo.Size.X - sbinfo.CursorPosition.X
|
||||
else: # Clear from cursor position to end of line
|
||||
line_start = sbinfo.CursorPosition
|
||||
line_length = sbinfo.Size.X - sbinfo.CursorPosition.X
|
||||
chars_written = c_int()
|
||||
windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, c_wchar(' '), line_length, line_start, byref(chars_written))
|
||||
windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, line_length, line_start, byref(chars_written))
|
||||
|
||||
def clear_screen(self, param):
|
||||
mode = to_int(param, 0)
|
||||
sbinfo = self.screen_buffer_info()
|
||||
if mode == 1: # Clear from begining of screen to cursor position
|
||||
clear_start = COORD(0, 0)
|
||||
clear_length = sbinfo.CursorPosition.X * sbinfo.CursorPosition.Y
|
||||
elif mode == 2: # Clear entire screen and return cursor to home
|
||||
clear_start = COORD(0, 0)
|
||||
clear_length = sbinfo.Size.X * sbinfo.Size.Y
|
||||
windll.kernel32.SetConsoleCursorPosition(self.hconsole, clear_start)
|
||||
else: # Clear from cursor position to end of screen
|
||||
clear_start = sbinfo.CursorPosition
|
||||
clear_length = ((sbinfo.Size.X - sbinfo.CursorPosition.X) + sbinfo.Size.X * (sbinfo.Size.Y - sbinfo.CursorPosition.Y))
|
||||
chars_written = c_int()
|
||||
windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, c_wchar(' '), clear_length, clear_start, byref(chars_written))
|
||||
windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, clear_length, clear_start, byref(chars_written))
|
||||
|
||||
def push_cursor(self, param):
|
||||
sbinfo = self.screen_buffer_info()
|
||||
self.cursor_history.append(sbinfo.CursorPosition)
|
||||
|
||||
def pop_cursor(self, param):
|
||||
if self.cursor_history:
|
||||
old_pos = self.cursor_history.pop()
|
||||
windll.kernel32.SetConsoleCursorPosition(self.hconsole, old_pos)
|
||||
|
||||
def set_cursor(self, param):
|
||||
y, sep, x = param.partition(';')
|
||||
x = to_int(x, 1) - 1
|
||||
y = to_int(y, 1) - 1
|
||||
sbinfo = self.screen_buffer_info()
|
||||
new_pos = COORD(
|
||||
min(max(0, x), sbinfo.Size.X),
|
||||
min(max(0, y), sbinfo.Size.Y)
|
||||
)
|
||||
windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)
|
||||
|
||||
def set_column(self, param):
|
||||
x = to_int(param, 1) - 1
|
||||
sbinfo = self.screen_buffer_info()
|
||||
new_pos = COORD(
|
||||
min(max(0, x), sbinfo.Size.X),
|
||||
sbinfo.CursorPosition.Y
|
||||
)
|
||||
windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)
|
||||
|
||||
def move_cursor(self, x_offset=0, y_offset=0):
|
||||
sbinfo = self.screen_buffer_info()
|
||||
new_pos = COORD(
|
||||
min(max(0, sbinfo.CursorPosition.X + x_offset), sbinfo.Size.X),
|
||||
min(max(0, sbinfo.CursorPosition.Y + y_offset), sbinfo.Size.Y)
|
||||
)
|
||||
windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)
|
||||
|
||||
def move_up(self, param):
|
||||
self.move_cursor(y_offset = -to_int(param, 1))
|
||||
|
||||
def move_down(self, param):
|
||||
self.move_cursor(y_offset = to_int(param, 1))
|
||||
|
||||
def move_left(self, param):
|
||||
self.move_cursor(x_offset = -to_int(param, 1))
|
||||
|
||||
def move_right(self, param):
|
||||
self.move_cursor(x_offset = to_int(param, 1))
|
||||
|
||||
def next_line(self, param):
|
||||
sbinfo = self.screen_buffer_info()
|
||||
self.move_cursor(
|
||||
x_offset = -sbinfo.CursorPosition.X,
|
||||
y_offset = to_int(param, 1)
|
||||
)
|
||||
|
||||
def prev_line(self, param):
|
||||
sbinfo = self.screen_buffer_info()
|
||||
self.move_cursor(
|
||||
x_offset = -sbinfo.CursorPosition.X,
|
||||
y_offset = -to_int(param, 1)
|
||||
)
|
||||
|
||||
def rgb2bgr(self, c):
|
||||
return ((c&1) << 2) | (c&2) | ((c&4)>>2)
|
||||
|
||||
def set_color(self, param):
|
||||
cols = param.split(';')
|
||||
sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
|
||||
windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))
|
||||
attr = sbinfo.Attributes
|
||||
for c in cols:
|
||||
if is_vista:
|
||||
c = int(c)
|
||||
else:
|
||||
c = to_int(c, 0)
|
||||
if c in range(30,38): # fgcolor
|
||||
attr = (attr & 0xfff0) | self.rgb2bgr(c-30)
|
||||
elif c in range(40,48): # bgcolor
|
||||
attr = (attr & 0xff0f) | (self.rgb2bgr(c-40) << 4)
|
||||
elif c == 0: # reset
|
||||
attr = self.orig_sbinfo.Attributes
|
||||
elif c == 1: # strong
|
||||
attr |= 0x08
|
||||
elif c == 4: # blink not available -> bg intensity
|
||||
attr |= 0x80
|
||||
elif c == 7: # negative
|
||||
attr = (attr & 0xff88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4)
|
||||
windll.kernel32.SetConsoleTextAttribute(self.hconsole, attr)
|
||||
|
||||
def show_cursor(self,param):
|
||||
csinfo.bVisible = 1
|
||||
windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(csinfo))
|
||||
|
||||
def hide_cursor(self,param):
|
||||
csinfo.bVisible = 0
|
||||
windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(csinfo))
|
||||
|
||||
ansi_command_table = {
|
||||
'A': move_up,
|
||||
'B': move_down,
|
||||
'C': move_right,
|
||||
'D': move_left,
|
||||
'E': next_line,
|
||||
'F': prev_line,
|
||||
'G': set_column,
|
||||
'H': set_cursor,
|
||||
'f': set_cursor,
|
||||
'J': clear_screen,
|
||||
'K': clear_line,
|
||||
'h': show_cursor,
|
||||
'l': hide_cursor,
|
||||
'm': set_color,
|
||||
's': push_cursor,
|
||||
'u': pop_cursor,
|
||||
}
|
||||
# Match either the escape sequence or text not containing escape sequence
|
||||
ansi_tokens = re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))')
|
||||
def write(self, text):
|
||||
try:
|
||||
wlock.acquire()
|
||||
for param, cmd, txt in self.ansi_tokens.findall(text):
|
||||
if cmd:
|
||||
cmd_func = self.ansi_command_table.get(cmd)
|
||||
if cmd_func:
|
||||
cmd_func(self, param)
|
||||
else:
|
||||
self.writeconsole(txt)
|
||||
finally:
|
||||
wlock.release()
|
||||
|
||||
def writeconsole(self, txt):
|
||||
chars_written = c_int()
|
||||
writeconsole = windll.kernel32.WriteConsoleA
|
||||
if isinstance(txt, _type):
|
||||
writeconsole = windll.kernel32.WriteConsoleW
|
||||
|
||||
TINY_STEP = 3000
|
||||
for x in range(0, len(txt), TINY_STEP):
|
||||
# According MSDN, size should NOT exceed 64 kb (issue #746)
|
||||
tiny = txt[x : x + TINY_STEP]
|
||||
writeconsole(self.hconsole, tiny, len(tiny), byref(chars_written), None)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def isatty(self):
|
||||
return True
|
||||
|
||||
sys.stderr = sys.stdout = AnsiTerm()
|
||||
os.environ['TERM'] = 'vt100'
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2010 (ita)
|
||||
|
||||
"""
|
||||
burn a book, save a tree
|
||||
"""
|
||||
|
||||
import os
|
||||
all_modifs = {}
|
||||
|
||||
def fixdir(dir):
|
||||
"""call all the substitution functions on the waf folders"""
|
||||
global all_modifs
|
||||
for k in all_modifs:
|
||||
for v in all_modifs[k]:
|
||||
modif(os.path.join(dir, 'waflib'), k, v)
|
||||
|
||||
def modif(dir, name, fun):
|
||||
"""execute a substitution function"""
|
||||
if name == '*':
|
||||
lst = []
|
||||
for y in '. Tools extras'.split():
|
||||
for x in os.listdir(os.path.join(dir, y)):
|
||||
if x.endswith('.py'):
|
||||
lst.append(y + os.sep + x)
|
||||
for x in lst:
|
||||
modif(dir, x, fun)
|
||||
return
|
||||
|
||||
filename = os.path.join(dir, name)
|
||||
f = open(filename, 'r')
|
||||
try:
|
||||
txt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
txt = fun(txt)
|
||||
|
||||
f = open(filename, 'w')
|
||||
try:
|
||||
f.write(txt)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def subst(*k):
|
||||
"""register a substitution function"""
|
||||
def do_subst(fun):
|
||||
global all_modifs
|
||||
for x in k:
|
||||
try:
|
||||
all_modifs[x].append(fun)
|
||||
except KeyError:
|
||||
all_modifs[x] = [fun]
|
||||
return fun
|
||||
return do_subst
|
||||
|
||||
@subst('*')
|
||||
def r1(code):
|
||||
"utf-8 fixes for python < 2.6"
|
||||
code = code.replace('as e:', ',e:')
|
||||
code = code.replace(".decode(sys.stdout.encoding or 'iso8859-1')", '')
|
||||
code = code.replace('.encode()', '')
|
||||
return code
|
||||
|
||||
@subst('Runner.py')
|
||||
def r4(code):
|
||||
"generator syntax"
|
||||
code = code.replace('next(self.biter)', 'self.biter.next()')
|
||||
return code
|
||||
|
||||
Vendored
+378
@@ -0,0 +1,378 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005-2010
|
||||
|
||||
"""
|
||||
to make a custom waf file use the option --tools
|
||||
|
||||
To add a tool that does not exist in the folder compat15, pass an absolute path:
|
||||
./waf-light --make-waf --tools=compat15,/comp/waf/aba.py --prelude=$'\tfrom waflib.extras import aba\n\taba.foo()'
|
||||
"""
|
||||
|
||||
|
||||
VERSION="1.7.11"
|
||||
APPNAME='waf'
|
||||
REVISION=''
|
||||
|
||||
top = '.'
|
||||
out = 'build'
|
||||
|
||||
demos = ['cpp', 'qt4', 'tex', 'ocaml', 'kde3', 'adv', 'cc', 'idl', 'docbook', 'xmlwaf', 'gnome']
|
||||
zip_types = ['bz2', 'gz']
|
||||
|
||||
PRELUDE = ''
|
||||
|
||||
#from tokenize import *
|
||||
import tokenize
|
||||
|
||||
import os, sys, re, io, optparse
|
||||
|
||||
from waflib import Utils, Options, Logs
|
||||
from hashlib import md5
|
||||
|
||||
from waflib import Configure
|
||||
Configure.autoconfig = 1
|
||||
|
||||
def sub_file(fname, lst):
|
||||
|
||||
f = open(fname, 'rU')
|
||||
try:
|
||||
txt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
for (key, val) in lst:
|
||||
re_pat = re.compile(key, re.M)
|
||||
txt = re_pat.sub(val, txt)
|
||||
|
||||
f = open(fname, 'w')
|
||||
try:
|
||||
f.write(txt)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def to_bytes(x):
|
||||
if sys.hexversion>0x300000f:
|
||||
return x.encode()
|
||||
return x
|
||||
|
||||
def init(ctx):
|
||||
if Options.options.setver: # maintainer only (ita)
|
||||
ver = Options.options.setver
|
||||
hexver = Utils.num2ver(ver)
|
||||
hexver = '0x%x'%hexver
|
||||
sub_file('wscript', (('^VERSION=(.*)', 'VERSION="%s"' % ver), ))
|
||||
sub_file('waf-light', (('^VERSION=(.*)', 'VERSION="%s"' % ver), ))
|
||||
|
||||
pats = []
|
||||
pats.append(('^WAFVERSION=(.*)', 'WAFVERSION="%s"' % ver))
|
||||
pats.append(('^HEXVERSION(.*)', 'HEXVERSION=%s' % hexver))
|
||||
|
||||
try:
|
||||
rev = ctx.cmd_and_log("git rev-parse HEAD").strip()
|
||||
pats.append(('^WAFREVISION(.*)', 'WAFREVISION="%s"' % rev))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sub_file('waflib/Context.py', pats)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
def check(ctx):
|
||||
Logs.warn('Nothing to do')
|
||||
|
||||
# this function is called before any other for parsing the command-line
|
||||
def options(opt):
|
||||
|
||||
# generate waf
|
||||
opt.add_option('--make-waf', action='store_true', default=False,
|
||||
help='creates the waf script', dest='waf')
|
||||
|
||||
opt.add_option('--zip-type', action='store', default='bz2',
|
||||
help='specify the zip type [Allowed values: %s]' % ' '.join(zip_types), dest='zip')
|
||||
|
||||
opt.add_option('--make-batch', action='store_true', default=False,
|
||||
help='creates a convenience waf.bat file (done automatically on win32 systems)',
|
||||
dest='make_batch')
|
||||
|
||||
opt.add_option('--yes', action='store_true', default=False,
|
||||
help=optparse.SUPPRESS_HELP,
|
||||
dest='yes')
|
||||
|
||||
# those ones are not too interesting
|
||||
opt.add_option('--set-version', default='',
|
||||
help='sets the version number for waf releases (for the maintainer)', dest='setver')
|
||||
|
||||
opt.add_option('--strip', action='store_true', default=True,
|
||||
help='shrinks waf (strip docstrings, saves 33kb)',
|
||||
dest='strip_comments')
|
||||
opt.add_option('--nostrip', action='store_false', help='no shrinking',
|
||||
dest='strip_comments')
|
||||
opt.add_option('--tools', action='store', help='Comma-separated 3rd party tools to add, eg: "compat,ocaml" [Default: "compat15"]',
|
||||
dest='add3rdparty', default='compat15')
|
||||
opt.add_option('--prelude', action='store', help='Code to execute before calling waf', dest='prelude', default=PRELUDE)
|
||||
opt.load('python')
|
||||
|
||||
def compute_revision():
|
||||
global REVISION
|
||||
|
||||
def visit(arg, dirname, names):
|
||||
for pos, name in enumerate(names):
|
||||
if name[0] == '.' or name in ['_build_', 'build']:
|
||||
del names[pos]
|
||||
elif name.endswith('.py'):
|
||||
arg.append(os.path.join(dirname, name))
|
||||
sources = []
|
||||
os.path.walk('waflib', visit, sources)
|
||||
sources.sort()
|
||||
m = md5()
|
||||
for source in sources:
|
||||
f = open(source,'rb')
|
||||
readBytes = 100000
|
||||
while (readBytes):
|
||||
readString = f.read(readBytes)
|
||||
m.update(readString)
|
||||
readBytes = len(readString)
|
||||
f.close()
|
||||
REVISION = m.hexdigest()
|
||||
|
||||
def process_tokens(tokens):
|
||||
accu = []
|
||||
prev = tokenize.NEWLINE
|
||||
|
||||
indent = 0
|
||||
line_buf = []
|
||||
|
||||
for (type, token, start, end, line) in tokens:
|
||||
token = token.replace('\r\n', '\n')
|
||||
if type == tokenize.NEWLINE:
|
||||
if line_buf:
|
||||
accu.append(indent * '\t')
|
||||
ln = "".join(line_buf)
|
||||
if ln == 'if __name__=="__main__":': break
|
||||
#ln = ln.replace('\n', '')
|
||||
accu.append(ln)
|
||||
accu.append('\n')
|
||||
line_buf = []
|
||||
prev = tokenize.NEWLINE
|
||||
elif type == tokenize.INDENT:
|
||||
indent += 1
|
||||
elif type == tokenize.DEDENT:
|
||||
indent -= 1
|
||||
elif type == tokenize.NAME:
|
||||
if prev == tokenize.NAME or prev == tokenize.NUMBER: line_buf.append(' ')
|
||||
line_buf.append(token)
|
||||
elif type == tokenize.NUMBER:
|
||||
if prev == tokenize.NAME or prev == tokenize.NUMBER: line_buf.append(' ')
|
||||
line_buf.append(token)
|
||||
elif type == tokenize.STRING:
|
||||
if not line_buf and token.startswith('"'): pass
|
||||
else: line_buf.append(token)
|
||||
elif type == tokenize.COMMENT:
|
||||
pass
|
||||
elif type == tokenize.OP:
|
||||
line_buf.append(token)
|
||||
else:
|
||||
if token != "\n": line_buf.append(token)
|
||||
|
||||
if token != '\n':
|
||||
prev = type
|
||||
|
||||
body = "".join(accu)
|
||||
return body
|
||||
|
||||
deco_re = re.compile('(def|class)\\s+(\w+)\\(.*')
|
||||
def process_decorators(body):
|
||||
lst = body.split('\n')
|
||||
accu = []
|
||||
all_deco = []
|
||||
buf = [] # put the decorator lines
|
||||
for line in lst:
|
||||
if line.startswith('@'):
|
||||
buf.append(line[1:])
|
||||
elif buf:
|
||||
name = deco_re.sub('\\2', line)
|
||||
if not name:
|
||||
raise IOError("decorator not followed by a function!" + line)
|
||||
for x in buf:
|
||||
all_deco.append("%s(%s)" % (x, name))
|
||||
accu.append(line)
|
||||
buf = []
|
||||
else:
|
||||
accu.append(line)
|
||||
return "\n".join(accu+all_deco)
|
||||
|
||||
def sfilter(path):
|
||||
|
||||
if path.endswith('.py') :
|
||||
if Options.options.strip_comments:
|
||||
if sys.version_info[0] >= 3:
|
||||
f = open(path, "rb")
|
||||
try:
|
||||
tk = tokenize.tokenize(f.readline)
|
||||
next(tk) # the first one is always tokenize.ENCODING for Python 3, ignore it
|
||||
cnt = process_tokens(tk)
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
f = open(path, "r")
|
||||
try:
|
||||
cnt = process_tokens(tokenize.generate_tokens(f.readline))
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
f = open(path, "r")
|
||||
try:
|
||||
cnt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
# WARNING: since we now require python 2.4, we do not process the decorators anymore
|
||||
# if you need such a thing, uncomment the code below:
|
||||
#cnt = process_decorators(cnt)
|
||||
#if cnt.find('set(') > -1:
|
||||
# cnt = 'import sys\nif sys.hexversion < 0x020400f0: from sets import Set as set\n' + cnt
|
||||
cnt = '#! /usr/bin/env python\n# encoding: utf-8\n# WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file\n\n' + cnt
|
||||
|
||||
else:
|
||||
f = open(path, "r")
|
||||
try:
|
||||
cnt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
if sys.hexversion > 0x030000f0:
|
||||
return (io.BytesIO(cnt.encode('utf-8')), len(cnt), cnt)
|
||||
return (io.BytesIO(cnt), len(cnt), cnt)
|
||||
|
||||
def create_waf(*k, **kw):
|
||||
mw = 'tmp-waf-'+VERSION
|
||||
|
||||
import tarfile, re
|
||||
|
||||
zipType = Options.options.zip.strip().lower()
|
||||
if zipType not in zip_types:
|
||||
zipType = zip_types[0]
|
||||
|
||||
#open a file as tar.[extension] for writing
|
||||
tar = tarfile.open('%s.tar.%s' % (mw, zipType), "w:%s" % zipType)
|
||||
|
||||
files = []
|
||||
add3rdparty = []
|
||||
for x in Options.options.add3rdparty.split(','):
|
||||
if os.path.isabs(x):
|
||||
files.append(x)
|
||||
else:
|
||||
add3rdparty.append(x + '.py')
|
||||
|
||||
for d in '. Tools extras'.split():
|
||||
dd = os.path.join('waflib', d)
|
||||
for k in os.listdir(dd):
|
||||
if k == '__init__.py':
|
||||
files.append(os.path.join(dd, k))
|
||||
continue
|
||||
if d == 'extras':
|
||||
if not k in add3rdparty:
|
||||
continue
|
||||
if k.endswith('.py'):
|
||||
files.append(os.path.join(dd, k))
|
||||
|
||||
for x in files:
|
||||
tarinfo = tar.gettarinfo(x, x)
|
||||
tarinfo.uid = tarinfo.gid = 0
|
||||
tarinfo.uname = tarinfo.gname = 'root'
|
||||
(code, size, cnt) = sfilter(x)
|
||||
tarinfo.size = size
|
||||
|
||||
if os.path.isabs(x):
|
||||
tarinfo.name = 'waflib/extras/' + os.path.split(x)[1]
|
||||
|
||||
tar.addfile(tarinfo, code)
|
||||
tar.close()
|
||||
|
||||
f = open('waf-light', 'rU')
|
||||
try:
|
||||
code1 = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
# now store the revision unique number in waf
|
||||
#compute_revision()
|
||||
#reg = re.compile('^REVISION=(.*)', re.M)
|
||||
#code1 = reg.sub(r'REVISION="%s"' % REVISION, code1)
|
||||
code1 = code1.replace("if sys.hexversion<0x206000f:\n\traise ImportError('Python >= 2.6 is required to create the waf file')\n", '')
|
||||
code1 = code1.replace('\t#import waflib.extras.compat15#PRELUDE', Options.options.prelude)
|
||||
|
||||
prefix = ''
|
||||
reg = re.compile('^INSTALL=(.*)', re.M)
|
||||
code1 = reg.sub(r'INSTALL=%r' % prefix, code1)
|
||||
#change the tarfile extension in the waf script
|
||||
reg = re.compile('bz2', re.M)
|
||||
code1 = reg.sub(zipType, code1)
|
||||
if zipType == 'gz':
|
||||
code1 = code1.replace('bunzip2', 'gzip -d')
|
||||
|
||||
f = open('%s.tar.%s' % (mw, zipType), 'rb')
|
||||
try:
|
||||
cnt = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
# the REVISION value is the md5 sum of the binary blob (facilitate audits)
|
||||
m = md5()
|
||||
m.update(cnt)
|
||||
REVISION = m.hexdigest()
|
||||
reg = re.compile('^REVISION=(.*)', re.M)
|
||||
code1 = reg.sub(r'REVISION="%s"' % REVISION, code1)
|
||||
|
||||
def find_unused(kd, ch):
|
||||
for i in range(35, 125):
|
||||
for j in range(35, 125):
|
||||
if i==j: continue
|
||||
if i == 39 or j == 39: continue
|
||||
if i == 92 or j == 92: continue
|
||||
s = chr(i) + chr(j)
|
||||
if -1 == kd.find(s.encode()):
|
||||
return (kd.replace(ch.encode(), s.encode()), s)
|
||||
raise
|
||||
|
||||
# The reverse order prevent collisions
|
||||
(cnt, C2) = find_unused(cnt, '\r')
|
||||
(cnt, C1) = find_unused(cnt, '\n')
|
||||
ccc = code1.replace("C1='x'", "C1='%s'" % C1).replace("C2='x'", "C2='%s'" % C2)
|
||||
|
||||
f = open('waf', 'wb')
|
||||
try:
|
||||
f.write(ccc.encode())
|
||||
f.write(to_bytes('#==>\n#'))
|
||||
f.write(cnt)
|
||||
f.write(to_bytes('\n#<==\n'))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
if sys.platform == 'win32' or Options.options.make_batch:
|
||||
f = open('waf.bat', 'w')
|
||||
try:
|
||||
f.write('@python -x "%~dp0waf" %* & exit /b\n')
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
if sys.platform != 'win32':
|
||||
os.chmod('waf', Utils.O755)
|
||||
os.remove('%s.tar.%s' % (mw, zipType))
|
||||
|
||||
def make_copy(inf, outf):
|
||||
(a, b, cnt) = sfilter(inf)
|
||||
f = open(outf, "wb")
|
||||
try:
|
||||
f.write(cnt)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def configure(conf):
|
||||
conf.load('python')
|
||||
conf.check_python_version((2,4))
|
||||
|
||||
def build(bld):
|
||||
waf = bld.path.make_node('waf') # create the node right here
|
||||
bld(name='create_waf', rule=create_waf, target=waf, always=True, color='PINK', update_outputs=True)
|
||||
|
||||
Reference in New Issue
Block a user