Unverified Commit bb8e7497 authored by Karl Linden's avatar Karl Linden
Browse files

Update to waf 1.8.17.

parent f3cf9d6f
......@@ -134,4 +134,5 @@ WAFLIB_STRIP_EXTRAS="
why
win32_opts
xcode
xcode6
"
......@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
import os, sys, inspect
VERSION="1.8.14"
VERSION="1.8.17"
REVISION="x"
GIT="x"
INSTALL="x"
......
......@@ -44,6 +44,10 @@ POST_LAZY = 1
POST_BOTH = 2
"""Post mode: post the task generators at once, then re-check them for each group"""
PROTOCOL = -1
if sys.platform == 'cli':
PROTOCOL = 0
class BuildContext(Context.Context):
'''executes the build'''
......@@ -322,7 +326,7 @@ class BuildContext(Context.Context):
try:
waflib.Node.pickle_lock.acquire()
waflib.Node.Nod3 = self.node_class
x = cPickle.dumps(data, -1)
x = cPickle.dumps(data, PROTOCOL)
finally:
waflib.Node.pickle_lock.release()
......@@ -821,17 +825,10 @@ class inst(Task.Task):
else:
y = self.path.find_resource(x)
if not y:
if Logs.verbose:
Logs.warn('Could not find %s immediately (may cause broken builds)' % x)
idx = self.generator.bld.get_group_idx(self)
for tg in self.generator.bld.groups[idx]:
if not isinstance(tg, inst) and id(tg) != id(self):
tg.post()
y = self.path.find_resource(x)
if y:
break
if os.path.isabs(x):
y = self.bld.root.make_node(x)
else:
raise Errors.WafError('Could not find %r in %r' % (x, self.path))
y = self.path.make_node(x)
buf.append(y)
self.inputs = buf
......@@ -1039,6 +1036,7 @@ class InstallContext(BuildContext):
:param postpone: execute the task immediately to perform the installation
:type postpone: bool
"""
assert(dest)
tsk = inst(env=env or self.env)
tsk.bld = self
tsk.path = cwd or self.path
......@@ -1075,6 +1073,7 @@ class InstallContext(BuildContext):
:param postpone: execute the task immediately to perform the installation
:type postpone: bool
"""
assert(dest)
tsk = inst(env=env or self.env)
tsk.bld = self
tsk.path = cwd or self.path
......@@ -1107,11 +1106,11 @@ class InstallContext(BuildContext):
:param relative_trick: make the symlink relative (default: ``False``)
:type relative_trick: bool
"""
if Utils.is_win32:
# symlinks *cannot* work on that platform
# TODO waf 1.9 - replace by install_as
return
assert(dest)
tsk = inst(env=env or self.env)
tsk.bld = self
tsk.dest = dest
......
......@@ -151,14 +151,8 @@ class ConfigurationContext(Context.Context):
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())
params = {'now': time.ctime(), 'pyver': sys.hexversion, 'systype': sys.platform, 'args': " ".join(sys.argv), 'wafver': Context.WAFVERSION, 'abi': Context.ABI, 'app': app}
self.to_log(conf_template % params)
self.msg('Setting top to', self.srcnode.abspath())
self.msg('Setting out to', self.bldnode.abspath())
......@@ -208,17 +202,17 @@ class ConfigurationContext(Context.Context):
"""
if not env.PREFIX:
if Options.options.prefix or Utils.is_win32:
env.PREFIX = os.path.abspath(os.path.expanduser(Options.options.prefix))
env.PREFIX = Utils.sane_path(Options.options.prefix)
else:
env.PREFIX = ''
if not env.BINDIR:
if Options.options.bindir:
env.BINDIR = os.path.abspath(os.path.expanduser(Options.options.bindir))
env.BINDIR = Utils.sane_path(Options.options.bindir)
else:
env.BINDIR = Utils.subst_vars('${PREFIX}/bin', env)
if not env.LIBDIR:
if Options.options.libdir:
env.LIBDIR = os.path.abspath(os.path.expanduser(Options.options.libdir))
env.LIBDIR = Utils.sane_path(Options.options.libdir)
else:
env.LIBDIR = Utils.subst_vars('${PREFIX}/lib%s' % Utils.lib64(), env)
......@@ -347,6 +341,7 @@ def conf(f):
if mandatory:
raise
fun.__name__ = f.__name__
setattr(ConfigurationContext, f.__name__, fun)
setattr(Build.BuildContext, f.__name__, fun)
return f
......@@ -422,7 +417,7 @@ def find_file(self, filename, path_list=[]):
"""
for n in Utils.to_list(filename):
for d in Utils.to_list(path_list):
p = os.path.join(d, n)
p = os.path.expanduser(os.path.join(d, n))
if os.path.exists(p):
return p
self.fatal('Could not find %r' % filename)
......@@ -529,7 +524,6 @@ def find_binary(self, filenames, exts, paths):
return x
return None
@conf
def run_build(self, *k, **kw):
"""
......
......@@ -11,13 +11,13 @@ from waflib import Utils, Errors, Logs
import waflib.Node
# the following 3 constants are updated on each new release (do not touch)
HEXVERSION=0x1080e00
HEXVERSION=0x1081100
"""Constant updated on new releases"""
WAFVERSION="1.8.14"
WAFVERSION="1.8.17"
"""Constant updated on new releases"""
WAFREVISION="ce8234c396bb246a20ea9f51594ee051d5b378e7"
WAFREVISION="cd7579a727d1b390bf9cbf111c1b20e811370bc0"
"""Git revision when the waf version is updated"""
ABI = 98
......@@ -307,6 +307,10 @@ class Context(ctx):
elif not node:
if not mandatory:
continue
try:
os.listdir(d)
except OSError:
raise Errors.WafError('Cannot read the folder %r' % d)
raise Errors.WafError('No wscript file in directory %s' % d)
def exec_command(self, cmd, **kw):
......@@ -610,7 +614,7 @@ class Context(ctx):
doban = False
for b in ban:
r = b.replace("*", ".*")
if re.match(b, f):
if re.match(r, f):
doban = True
if not doban:
f = f.replace('.py', '')
......
......@@ -6,7 +6,7 @@
logging, colors, terminal width and pretty-print
"""
import os, re, traceback, sys, types
import os, re, traceback, sys
from waflib import Utils, ansiterm
if not os.environ.get('NOSYNC', False):
......@@ -43,6 +43,11 @@ colors_lst = {
indicator = '\r\x1b[K%s%s%s'
try:
unicode
except NameError:
unicode = None
def enable_colors(use):
if use == 1:
if not (sys.stderr.isatty() or sys.stdout.isatty()):
......@@ -150,7 +155,7 @@ class log_handler(logging.StreamHandler):
def emit_override(self, record, **kw):
self.terminator = getattr(record, 'terminator', '\n')
stream = self.stream
if hasattr(types, "UnicodeType"):
if unicode:
# python2
msg = self.formatter.format(record)
fs = '%s' + self.terminator
......@@ -316,7 +321,7 @@ def free_logger(logger):
for x in logger.handlers:
x.close()
logger.removeHandler(x)
except Exception as e:
except Exception:
pass
def pprint(col, msg, label='', sep='\n'):
......
......@@ -59,14 +59,11 @@ Ant patterns for files and folders to exclude while doing the
recursive traversal in :py:meth:`waflib.Node.Node.ant_glob`
"""
# TODO waf 1.9
split_path = Utils.split_path_unix
# TODO remove in waf 1.9
split_path = Utils.split_path
split_path_unix = Utils.split_path_unix
split_path_cygwin = Utils.split_path_cygwin
split_path_win32 = Utils.split_path_win32
if sys.platform == 'cygwin':
split_path = split_path_cygwin
elif Utils.is_win32:
split_path = split_path_win32
class Node(object):
"""
......@@ -152,6 +149,69 @@ class Node(object):
"""
Utils.writef(self.abspath(), data, flags, encoding)
def read_json(self, convert=True, encoding='utf-8'):
"""
Read and parse the contents of this node as JSON::
def build(bld):
bld.path.find_node('abc.json').read_json()
Note that this by default automatically decodes unicode strings on Python2, unlike what the Python JSON module does.
:type convert: boolean
:param convert: Prevents decoding of unicode strings on Python2
:type encoding: string
:param encoding: The encoding of the file to read. This default to UTF8 as per the JSON standard
:rtype: object
:return: Parsed file contents
"""
import json # Python 2.6 and up
object_pairs_hook = None
if convert and sys.hexversion < 0x3000000:
try:
_type = unicode
except NameError:
_type = str
def convert(value):
if isinstance(value, list):
return [convert(element) for element in value]
elif isinstance(value, _type):
return str(value)
else:
return value
def object_pairs(pairs):
return dict((str(pair[0]), convert(pair[1])) for pair in pairs)
object_pairs_hook = object_pairs
return json.loads(self.read(encoding=encoding), object_pairs_hook=object_pairs_hook)
def write_json(self, data, pretty=True):
"""
Writes a python object as JSON to disk. Files are always written as UTF8 as per the JSON standard::
def build(bld):
bld.path.find_node('xyz.json').write_json(199)
:type data: object
:param data: The data to write to disk
:type pretty: boolean
:param pretty: Determines if the JSON will be nicely space separated
"""
import json # Python 2.6 and up
indent = 2
separators = (',', ': ')
sort_keys = pretty
newline = os.linesep
if not pretty:
indent = None
separators = (',', ':')
newline = ''
output = json.dumps(data, indent=indent, separators=separators, sort_keys=sort_keys) + newline
self.write(output, encoding='utf-8')
def chmod(self, val):
"""
Change file/dir permissions::
......@@ -251,7 +311,7 @@ class Node(object):
cur.children = self.dict_class()
else:
try:
cur = cur.children[x]
cur = ch[x]
continue
except KeyError:
pass
......
......@@ -256,7 +256,7 @@ class OptionsContext(Context.Context):
commands.append(arg)
if options.destdir:
options.destdir = os.path.abspath(os.path.expanduser(options.destdir))
options.destdir = Utils.sane_path(options.destdir)
if options.verbose >= 1:
self.load('errcheck')
......
......@@ -278,6 +278,13 @@ class Parallel(object):
:param tsk: task
:type tsk: :py:attr:`waflib.Task.TaskBase`
"""
if hasattr(tsk, 'scan') and hasattr(tsk, 'uid'):
# TODO waf 1.9 - this breaks encapsulation
key = (tsk.uid(), 'imp')
try:
del self.bld.task_sigs[key]
except KeyError:
pass
if not self.bld.keep:
self.stop = True
self.error.append(tsk)
......
......@@ -46,6 +46,7 @@ def waf_entry_point(current_directory, version, wafdir):
# perhaps extract 'wscript' as a constant
if os.path.basename(potential_wscript) == 'wscript' and os.path.isfile(potential_wscript):
# need to explicitly normalize the path, as it may contain extra '/.'
# TODO abspath?
current_directory = os.path.normpath(os.path.dirname(potential_wscript))
sys.argv.pop(1)
......@@ -62,11 +63,14 @@ def waf_entry_point(current_directory, version, wafdir):
break
# if --top is provided assume the build started in the top directory
for x in sys.argv:
for i, x in enumerate(sys.argv):
# WARNING: this modifies sys.argv
if x.startswith('--top='):
Context.run_dir = Context.top_dir = x[6:]
Context.run_dir = Context.top_dir = Utils.sane_path(x[6:])
sys.argv[i] = '--top=' + Context.run_dir
if x.startswith('--out='):
Context.out_dir = x[6:]
Context.out_dir = Utils.sane_path(x[6:])
sys.argv[i] = '--out=' + Context.out_dir
# try to find a lock file (if the project was configured)
# at the same time, store the first wscript file seen
......@@ -137,7 +141,7 @@ def waf_entry_point(current_directory, version, wafdir):
sys.exit(1)
try:
set_main_module(os.path.join(Context.run_dir, Context.WSCRIPT_FILE))
set_main_module(os.path.normpath(os.path.join(Context.run_dir, Context.WSCRIPT_FILE)))
except Errors.WafError as e:
Logs.pprint('RED', e.verbose_msg)
Logs.error(str(e))
......
......@@ -37,11 +37,14 @@ SKIP_ME = -2
RUN_ME = -3
"""The task must be executed"""
# To save some memory during the build, consider discarding tsk.last_cmd in the two templates below
COMPILE_TEMPLATE_SHELL = '''
def f(tsk):
env = tsk.env
gen = tsk.generator
bld = gen.bld
cwdx = getattr(bld, 'cwdx', bld.bldnode) # TODO single cwd value in waf 1.9
wd = getattr(tsk, 'cwd', None)
p = env.get_flat
tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s
......@@ -53,6 +56,7 @@ def f(tsk):
env = tsk.env
gen = tsk.generator
bld = gen.bld
cwdx = getattr(bld, 'cwdx', bld.bldnode) # TODO single cwd value in waf 1.9
wd = getattr(tsk, 'cwd', None)
def to_list(xx):
if isinstance(xx, str): return [xx]
......@@ -81,11 +85,10 @@ class store_task_type(type):
name = name.replace('_task', '')
if name != 'evil' and name != 'TaskBase':
global classes
if getattr(cls, 'run_str', None):
# if a string is provided, convert it to a method
(f, dvars) = compile_fun(cls.run_str, cls.shell)
cls.hcode = cls.run_str
cls.hcode = Utils.h_cmd(cls.run_str)
cls.orig_run_str = cls.run_str
# change the name of run_str or it is impossible to subclass with a function
cls.run_str = None
......@@ -94,10 +97,7 @@ class store_task_type(type):
cls.vars.sort()
elif getattr(cls, 'run', None) and not 'hcode' in cls.__dict__:
# getattr(cls, 'hcode') would look in the upper classes
cls.hcode = Utils.h_fun(cls.run)
if sys.hexversion > 0x3000000:
cls.hcode = cls.hcode.encode('iso8859-1', 'xmlcharrefreplace')
cls.hcode = Utils.h_cmd(cls.run)
# be creative
getattr(cls, 'register', classes)[name] = cls
......@@ -206,6 +206,7 @@ class TaskBase(evil):
# remove the task signature immediately before it is executed
# in case of failure the task will be executed again
try:
# TODO waf 1.9 - this breaks encapsulation
del self.generator.bld.task_sigs[self.uid()]
except KeyError:
pass
......@@ -972,17 +973,17 @@ def compile_fun_shell(line):
for (var, meth) in extr:
if var == 'SRC':
if meth: app('tsk.inputs%s' % meth)
else: app('" ".join([a.path_from(bld.bldnode) for a in tsk.inputs])')
else: app('" ".join([a.path_from(cwdx) for a in tsk.inputs])')
elif var == 'TGT':
if meth: app('tsk.outputs%s' % meth)
else: app('" ".join([a.path_from(bld.bldnode) for a in tsk.outputs])')
else: app('" ".join([a.path_from(cwdx) for a in tsk.outputs])')
elif meth:
if meth.startswith(':'):
m = meth[1:]
if m == 'SRC':
m = '[a.path_from(bld.bldnode) for a in tsk.inputs]'
m = '[a.path_from(cwdx) for a in tsk.inputs]'
elif m == 'TGT':
m = '[a.path_from(bld.bldnode) for a in tsk.outputs]'
m = '[a.path_from(cwdx) for a in tsk.outputs]'
elif m[:3] not in ('tsk', 'gen', 'bld'):
dvars.extend([var, meth[1:]])
m = '%r' % m
......@@ -1027,17 +1028,17 @@ def compile_fun_noshell(line):
(var, meth) = extr[x]
if var == 'SRC':
if meth: app('lst.append(tsk.inputs%s)' % meth)
else: app("lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])")
else: app("lst.extend([a.path_from(cwdx) for a in tsk.inputs])")
elif var == 'TGT':
if meth: app('lst.append(tsk.outputs%s)' % meth)
else: app("lst.extend([a.path_from(bld.bldnode) for a in tsk.outputs])")
else: app("lst.extend([a.path_from(cwdx) for a in tsk.outputs])")
elif meth:
if meth.startswith(':'):
m = meth[1:]
if m == 'SRC':
m = '[a.path_from(bld.bldnode) for a in tsk.inputs]'
m = '[a.path_from(cwdx) for a in tsk.inputs]'
elif m == 'TGT':
m = '[a.path_from(bld.bldnode) for a in tsk.outputs]'
m = '[a.path_from(cwdx) for a in tsk.outputs]'
elif m[:3] not in ('tsk', 'gen', 'bld'):
dvars.extend([var, m])
m = '%r' % m
......@@ -1074,9 +1075,27 @@ def compile_fun(line, shell=False):
The reserved keywords *TGT* and *SRC* represent the task input and output nodes
"""
if line.find('<') > 0 or line.find('>') > 0 or line.find('&&') > 0:
shell = True
if isinstance(line, str):
if line.find('<') > 0 or line.find('>') > 0 or line.find('&&') > 0:
shell = True
else:
dvars_lst = []
funs_lst = []
for x in line:
if isinstance(x, str):
fun, dvars = compile_fun(x, shell)
dvars_lst += dvars
funs_lst.append(fun)
else:
# assume a function to let through
funs_lst.append(x)
def composed_fun(task):
for x in funs_lst:
ret = x(task)
if ret:
return ret
return None
return composed_fun, dvars
if shell:
return compile_fun_shell(line)
else:
......@@ -1111,7 +1130,7 @@ def task_factory(name, func=None, vars=None, color='GREEN', ext_in=[], ext_out=[
'scan': scan,
}
if isinstance(func, str):
if isinstance(func, str) or isinstance(func, tuple):
params['run_str'] = func
else:
params['run'] = func
......
......@@ -564,7 +564,15 @@ def process_rule(self):
except KeyError:
pass
if not cls:
cls = Task.task_factory(name, self.rule,
rule = self.rule
if hasattr(self, 'chmod'):
def chmod_fun(tsk):
for x in tsk.outputs:
os.chmod(x.abspath(), self.chmod)
rule = (self.rule, chmod_fun)
cls = Task.task_factory(name, rule,
getattr(self, 'vars', []),
shell=getattr(self, 'shell', True), color=getattr(self, 'color', 'BLUE'),
scan = getattr(self, 'scan', None))
......@@ -614,7 +622,7 @@ def process_rule(self):
x.parent.mkdir() # if a node was given, create the required folders
tsk.outputs.append(x)
if getattr(self, 'install_path', None):
self.bld.install_files(self.install_path, tsk.outputs)
self.bld.install_files(self.install_path, tsk.outputs, chmod=getattr(self, 'chmod', Utils.O644))
if getattr(self, 'source', None):
tsk.inputs = self.to_nodes(self.source)
......@@ -669,24 +677,34 @@ class subst_pc(Task.Task):
in the substitution changes.
"""
def force_permissions(self):
"Private for the time being, we will probably refactor this into run_str=[run1,chmod]"
if getattr(self.generator, 'chmod', None):
for x in self.outputs:
os.chmod(x.abspath(), self.generator.chmod)
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)
for i, x in enumerate(self.outputs):
x.write(self.inputs[i].read('rb'), 'wb')
self.force_permissions()
return None
if getattr(self.generator, 'fun', None):
return self.generator.fun(self)
ret = self.generator.fun(self)
if not ret:
self.force_permissions()
return ret
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 is not None:
self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))
return
self.force_permissions()
return None
# replace all % by %% to prevent errors by % signs
code = code.replace('%', '%%')
......@@ -722,8 +740,7 @@ class subst_pc(Task.Task):
try: delattr(self, 'cache_sig')
except AttributeError: pass
if getattr(self.generator, 'chmod', None):
os.chmod(self.outputs[0].abspath(), self.generator.chmod)
self.force_permissions()
def sig_vars(self):
"""
......@@ -816,7 +833,7 @@ def process_subst(self):
b = y
if not a:
raise Errors.WafError('cound not find %r for %r' % (x, self))
raise Errors.WafError('could not find %r for %r' % (x, self))
has_constraints = False
tsk = self.create_task('subst', a, b)
......
......@@ -4,8 +4,7 @@
"base for all c/c++ programs and libraries"
import os, sys, re
from waflib import Utils, Build, Errors
from waflib import Utils, Errors
from waflib.Configure import conf
def get_extensions(lst):
......@@ -49,7 +48,7 @@ def sniff_features(**kw):
feats.append('cxx')
break
if 'c' in exts or 'vala' in exts: