Unverified Commit 8b8be738 authored by Karl Linden's avatar Karl Linden
Browse files

Update waf to 1.8.14

parent a3ad1ff9
......@@ -47,6 +47,7 @@ WAFLIB_STRIP_EXTRAS="
boo
boost
c_dumbpreproc
c_emscripten
cabal
cfg_altoptions
cfg_cross_gnu
......
......@@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
import os, sys, inspect
VERSION="1.8.9"
VERSION="1.8.14"
REVISION="x"
GIT="x"
INSTALL="x"
......
......@@ -1015,6 +1015,7 @@ class InstallContext(BuildContext):
if tsk.runnable_status() == Task.ASK_LATER:
raise self.WafError('cannot post the task %r' % tsk)
tsk.run()
tsk.hasrun = True
def install_files(self, dest, files, env=None, chmod=Utils.O644, relative_trick=False, cwd=None, add=True, postpone=True, task=None):
"""
......
......@@ -167,6 +167,7 @@ class ConfigSet(object):
for x in keys:
tbl[x] = copy.deepcopy(tbl[x])
self.table = tbl
return self
def get_flat(self, key):
"""
......
......@@ -192,11 +192,11 @@ class ConfigurationContext(Context.Context):
env['files'] = self.files
env['environ'] = dict(self.environ)
if not self.env.NO_LOCK_IN_RUN:
if not self.env.NO_LOCK_IN_RUN and not getattr(Options.options, 'no_lock_in_run'):
env.store(os.path.join(Context.run_dir, Options.lockfile))
if not self.env.NO_LOCK_IN_TOP:
if not self.env.NO_LOCK_IN_TOP and not getattr(Options.options, 'no_lock_in_top'):
env.store(os.path.join(Context.top_dir, Options.lockfile))
if not self.env.NO_LOCK_IN_OUT:
if not self.env.NO_LOCK_IN_OUT and not getattr(Options.options, 'no_lock_in_out'):
env.store(os.path.join(Context.out_dir, Options.lockfile))
def prepare_env(self, env):
......@@ -234,7 +234,7 @@ class ConfigurationContext(Context.Context):
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):
def load(self, input, tooldir=None, funs=None, with_sys_path=True):
"""
Load Waf tools, which will be imported whenever a build is started.
......@@ -252,7 +252,7 @@ class ConfigurationContext(Context.Context):
# avoid loading the same tool more than once with the same functions
# used by composite projects
mag = (tool, id(self.env), funs)
mag = (tool, id(self.env), tooldir, funs)
if mag in self.tool_cache:
self.to_log('(tool %s is already loaded, skipping)' % tool)
continue
......@@ -260,7 +260,7 @@ class ConfigurationContext(Context.Context):
module = None
try:
module = Context.load_tool(tool, tooldir, ctx=self)
module = Context.load_tool(tool, tooldir, ctx=self, with_sys_path=with_sys_path)
except ImportError as e:
self.fatal('Could not load the Waf tool %r from %r\n%s' % (tool, sys.path, e))
except Exception as e:
......@@ -352,7 +352,7 @@ def conf(f):
return f
@conf
def add_os_flags(self, var, dest=None):
def add_os_flags(self, var, dest=None, dup=True):
"""
Import operating system environment values into ``conf.env`` dict::
......@@ -363,10 +363,16 @@ def add_os_flags(self, var, dest=None):
:type var: string
:param dest: destination variable, by default the same as var
:type dest: string
:param dup: add the same set of flags again
:type dup: bool
"""
# 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
try:
flags = shlex.split(self.environ[var])
except KeyError:
return
# TODO: in waf 1.9, make dup=False the default
if dup or ''.join(flags) not in ''.join(Utils.to_list(self.env[dest or var])):
self.env.append_value(dest or var, flags)
@conf
def cmd_to_list(self, cmd):
......
......@@ -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=0x1080900
HEXVERSION=0x1080e00
"""Constant updated on new releases"""
WAFVERSION="1.8.9"
WAFVERSION="1.8.14"
"""Constant updated on new releases"""
WAFREVISION="06e49b2a82166aeb14dde8357c58387f252fc722"
WAFREVISION="ce8234c396bb246a20ea9f51594ee051d5b378e7"
"""Git revision when the waf version is updated"""
ABI = 98
......@@ -55,7 +55,7 @@ waf_dir = ''
local_repo = ''
"""Local repository containing additional Waf tools (plugins)"""
remote_repo = 'http://waf.googlecode.com/git/'
remote_repo = 'https://raw.githubusercontent.com/waf-project/waf/master/'
"""
Remote directory containing downloadable waf tools. The missing tools can be downloaded by using::
......@@ -210,9 +210,10 @@ class Context(ctx):
"""
tools = Utils.to_list(tool_list)
path = Utils.to_list(kw.get('tooldir', ''))
with_sys_path = kw.get('with_sys_path', True)
for t in tools:
module = load_tool(t, path)
module = load_tool(t, path, with_sys_path=with_sys_path)
fun = getattr(module, kw.get('name', self.fun), None)
if fun:
fun(self)
......@@ -321,11 +322,11 @@ class Context(ctx):
unlike :py:meth:`waflib.Context.Context.cmd_and_log`
:param cmd: command argument for subprocess.Popen
:param kw: keyword arguments for subprocess.Popen
:param kw: keyword arguments for subprocess.Popen. The parameters input/timeout will be passed to wait/communicate.
"""
subprocess = Utils.subprocess
kw['shell'] = isinstance(cmd, str)
Logs.debug('runner: %r' % cmd)
Logs.debug('runner: %r' % (cmd,))
Logs.debug('runner_env: kw=%s' % kw)
if self.logger:
......@@ -339,14 +340,25 @@ class Context(ctx):
if Logs.verbose and not kw['shell'] and not Utils.check_exe(cmd[0]):
raise Errors.WafError("Program %s not found!" % cmd[0])
wargs = {}
if 'timeout' in kw:
if kw['timeout'] is not None:
wargs['timeout'] = kw['timeout']
del kw['timeout']
if 'input' in kw:
if kw['input']:
wargs['input'] = kw['input']
kw['stdin'] = Utils.subprocess.PIPE
del kw['input']
try:
if kw['stdout'] or kw['stderr']:
p = subprocess.Popen(cmd, **kw)
(out, err) = p.communicate()
(out, err) = p.communicate(**wargs)
ret = p.returncode
else:
out, err = (None, None)
ret = subprocess.Popen(cmd, **kw).wait()
ret = subprocess.Popen(cmd, **kw).wait(**wargs)
except Exception as e:
raise Errors.WafError('Execution failure: %s' % str(e), ex=e)
......@@ -369,24 +381,25 @@ class Context(ctx):
def cmd_and_log(self, cmd, **kw):
"""
Execute a command and return stdout if the execution is successful.
Execute a command and return stdout/stderr 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)
(out, err) = conf.cmd_and_log(cmd, input='\\n'.encode(), output=waflib.Context.STDOUT)
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
:param kw: keyword arguments for subprocess.Popen. The parameters input/timeout will be passed to wait/communicate.
"""
subprocess = Utils.subprocess
kw['shell'] = isinstance(cmd, str)
Logs.debug('runner: %r' % cmd)
Logs.debug('runner: %r' % (cmd,))
if 'quiet' in kw:
quiet = kw['quiet']
......@@ -406,9 +419,21 @@ class Context(ctx):
kw['stdout'] = kw['stderr'] = subprocess.PIPE
if quiet is None:
self.to_log(cmd)
wargs = {}
if 'timeout' in kw:
if kw['timeout'] is not None:
wargs['timeout'] = kw['timeout']
del kw['timeout']
if 'input' in kw:
if kw['input']:
wargs['input'] = kw['input']
kw['stdin'] = Utils.subprocess.PIPE
del kw['input']
try:
p = subprocess.Popen(cmd, **kw)
(out, err) = p.communicate()
(out, err) = p.communicate(**wargs)
except Exception as e:
raise Errors.WafError('Execution failure: %s' % str(e), ex=e)
......@@ -620,14 +645,14 @@ def load_module(path, encoding=None):
module_dir = os.path.dirname(path)
sys.path.insert(0, module_dir)
exec(compile(code, path, 'exec'), module.__dict__)
sys.path.remove(module_dir)
try : exec(compile(code, path, 'exec'), module.__dict__)
finally: sys.path.remove(module_dir)
cache_modules[path] = module
return module
def load_tool(tool, tooldir=None, ctx=None):
def load_tool(tool, tooldir=None, ctx=None, with_sys_path=True):
"""
Import a Waf tool (python module), and store it in the dict :py:const:`waflib.Context.Context.tools`
......@@ -635,33 +660,44 @@ def load_tool(tool, tooldir=None, ctx=None):
:param tool: Name of the tool
:type tooldir: list
:param tooldir: List of directories to search for the tool module
:type with_sys_path: boolean
:param with_sys_path: whether or not to search the regular sys.path, besides waf_dir and potentially given tooldirs
"""
if tool == 'java':
tool = 'javaw' # jython
else:
tool = tool.replace('++', 'xx')
if tooldir:
assert isinstance(tooldir, list)
sys.path = tooldir + sys.path
try:
__import__(tool)
origSysPath = sys.path
if not with_sys_path: sys.path = []
try:
if tooldir:
assert isinstance(tooldir, list)
sys.path = tooldir + sys.path
try:
__import__(tool)
finally:
for d in tooldir:
sys.path.remove(d)
ret = sys.modules[tool]
Context.tools[tool] = ret
return ret
finally:
for d in tooldir:
sys.path.remove(d)
else:
for x in ('waflib.Tools.%s', 'waflib.extras.%s', 'waflib.%s', '%s'):
else:
if not with_sys_path: sys.path.insert(0, waf_dir)
try:
__import__(x % tool)
break
except ImportError:
x = None
if x is None: # raise an exception
__import__(tool)
ret = sys.modules[x % tool]
Context.tools[tool] = ret
return ret
for x in ('waflib.Tools.%s', 'waflib.extras.%s', 'waflib.%s', '%s'):
try:
__import__(x % tool)
break
except ImportError:
x = None
if x is None: # raise an exception
__import__(tool)
finally:
if not with_sys_path: sys.path.remove(waf_dir)
ret = sys.modules[x % tool]
Context.tools[tool] = ret
return ret
finally:
if not with_sys_path: sys.path += origSysPath
......@@ -20,8 +20,8 @@ if not os.environ.get('NOSYNC', False):
# in case someone uses the root logger
import logging
LOG_FORMAT = "%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s"
HOUR_FORMAT = "%H:%M:%S"
LOG_FORMAT = os.environ.get('WAF_LOG_FORMAT', '%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s')
HOUR_FORMAT = os.environ.get('WAF_HOUR_FORMAT', '%H:%M:%S')
zones = ''
verbose = 0
......@@ -35,6 +35,7 @@ colors_lst = {
'PINK' :'\x1b[35m',
'BLUE' :'\x1b[01;34m',
'CYAN' :'\x1b[36m',
'GREY' :'\x1b[37m',
'NORMAL':'\x1b[0m',
'cursor_on' :'\x1b[?25h',
'cursor_off' :'\x1b[?25l',
......
......@@ -126,6 +126,10 @@ class OptionsContext(Context.Context):
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')
gr.add_option('--no-lock-in-run', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_run')
gr.add_option('--no-lock-in-out', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_out')
gr.add_option('--no-lock-in-top', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_top')
default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX'))
if not default_prefix:
if platform == 'win32':
......
......@@ -61,10 +61,17 @@ def waf_entry_point(current_directory, version, wafdir):
no_climb = True
break
# if --top is provided assume the build started in the top directory
for x in sys.argv:
if x.startswith('--top='):
Context.run_dir = Context.top_dir = x[6:]
if x.startswith('--out='):
Context.out_dir = x[6:]
# 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:
while cur and not Context.top_dir:
lst = os.listdir(cur)
if Options.lockfile in lst:
env = ConfigSet.ConfigSet()
......@@ -557,16 +564,26 @@ def distcheck(ctx):
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')]
lst = Options.options.files
if lst:
lst = lst.split(',')
else:
path = os.path.join(Context.waf_dir, 'waflib', 'extras')
lst = [x for x in Utils.listdir(path) if x.endswith('.py')]
for x in lst:
tool = x.replace('.py', '')
if not tool:
continue
try:
dl = Configure.download_tool
except AttributeError:
ctx.fatal('The command "update" is dangerous; include the tool "use_config" in your project!')
try:
Configure.download_tool(tool, force=True, ctx=ctx)
dl(tool, force=True, ctx=ctx)
except Errors.WafError:
Logs.error('Could not find the tool %s in the remote repository' % x)
Logs.error('Could not find the tool %r in the remote repository' % x)
else:
Logs.warn('Updated %r' % tool)
def autoconfigure(execute_method):
"""
......
......@@ -64,7 +64,7 @@ def f(tsk):
'''
classes = {}
"class tasks created by user scripts or Waf tools are kept in this dict name -> class object"
"Class tasks created by user scripts or Waf tools (maps names to class objects). Task classes defined in Waf tools are registered here through the metaclass :py:class:`waflib.Task.store_task_type`."
class store_task_type(type):
"""
......@@ -118,6 +118,8 @@ class TaskBase(evil):
#. runnable_status: ask the task if it should be run, skipped, or if we have to ask later
#. run: let threads execute the task
#. post_run: let threads update the data regarding the task (cache)
.. warning:: For backward compatibility reasons, the suffix "_task" is truncated in derived class names. This limitation will be removed in Waf 1.9.
"""
color = 'GREEN'
......@@ -402,6 +404,8 @@ class Task(TaskBase):
uses a hash value (from :py:class:`waflib.Task.Task.signature`) which is persistent from build to build. When the value changes,
the task has to be executed. The method :py:class:`waflib.Task.Task.post_run` will assign the task signature to the output
nodes (if present).
.. warning:: For backward compatibility reasons, the suffix "_task" is truncated in derived class names. This limitation will be removed in Waf 1.9.
"""
vars = []
"""Variables to depend on (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""
......
......@@ -593,6 +593,12 @@ def process_rule(self):
if getattr(self, 'cache_rule', 'True'):
cache[(name, self.rule)] = cls
if getattr(self, 'cls_str', None):
setattr(cls, '__str__', self.cls_str)
if getattr(self, 'cls_keyword', None):
setattr(cls, 'keyword', self.cls_keyword)
# now create one instance
tsk = self.create_task(name)
......
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2015 (ita)
"base for all c/c++ programs and libraries"
import os, sys, re
from waflib import Utils, Build
from waflib import Utils, Build, Errors
from waflib.Configure import conf
def get_extensions(lst):
......@@ -44,26 +44,34 @@ def sniff_features(**kw):
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')
for x in 'cxx cpp c++ cc C'.split():
if x in exts:
feats.append('cxx')
break
if 'c' in exts or 'vala' in exts:
feats.append('c')
for x in 'f f90 F F90 for FOR'.split():
if x in exts:
feats.append('fc')
break
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'):
will_link = False
for x in feats:
if x in ('cxx', 'd', 'c'):
if x in ('cxx', 'd', 'fc', 'c'):
feats.append(x + type)
will_link = True
if not will_link and not kw.get('features', []):
raise Errors.WafError('Cannot link from %r, try passing eg: features="cprogram"?' % kw)
return feats
def set_features(kw, _type):
......
......@@ -25,10 +25,10 @@ cfg_ver = {
SNIP_FUNCTION = '''
int main(int argc, char **argv) {
void *p;
void (*p)();
(void)argc; (void)argv;
p=(void*)(%s);
return (int)p;
p=(void(*)())(%s);
return !p;
}
'''
"""Code template for checking for functions"""
......@@ -383,7 +383,9 @@ def check_cfg(self, *k, **kw):
conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL')
conf.check_cfg(path='mpicc', args='--showme:compile --showme:link',
package='', uselib_store='OPEN_MPI', mandatory=False)
# variables
conf.check_cfg(package='gtk+-2.0', variables=['includedir', 'prefix'], uselib_store='FOO')
print(conf.env.FOO_includedir)
"""
if k:
lst = k[0].split()
......@@ -587,6 +589,7 @@ def validate_c(self, kw):
kw['execute'] = False
if kw['execute']:
kw['features'].append('test_exec')
kw['chmod'] = 493
if not 'errmsg' in kw:
kw['errmsg'] = 'not found'
......@@ -661,6 +664,16 @@ def check(self, *k, **kw):
Perform a configuration test by calling :py:func:`waflib.Configure.run_build`.
For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
To force a specific compiler, pass "compiler='c'" or "compiler='cxx'" in the arguments
Besides build targets, complete builds can be given though a build function. All files will
be written to a temporary directory::
def build(bld):
lib_node = bld.srcnode.make_node('libdir/liblc1.c')
lib_node.parent.mkdir()
lib_node.write('#include <stdio.h>\\nint lib_func(void) { FILE *f = fopen("foo", "r");}\\n', 'w')
bld(features='c cshlib', source=[lib_node], linkflags=conf.env.EXTRA_LDFLAGS, target='liblc')
conf.check(build_fun=build, msg=msg)
"""
self.validate_c(kw)
self.start_msg(kw['msg'], **kw)
......@@ -855,7 +868,10 @@ def write_config_header(self, configfile='', guard='', top=False, defines=True,
cnf.define('A', 1)
cnf.write_config_header('config.h')
:param configfile: relative path to the file to create
This function only adds include guards (if necessary), consult
:py:func:`waflib.Tools.c_config.get_config_header` for details on the body.
:param configfile: path to the file to create (relative or absolute)
:type configfile: string
:param guard: include guard name to add, by default it is computed from the file name
:type guard: string
......@@ -884,7 +900,7 @@ def write_config_header(self, configfile='', guard='', top=False, defines=True,
node.write('\n'.join(lst))
# config files are not removed on "waf clean"
# config files must not be removed on "waf clean"
self.env.append_unique(Build.CFG_FILES, [node.abspath()])
if remove:
......@@ -898,9 +914,16 @@ def get_config_header(self, defines=True, headers=False, define_prefix=''):
Create the contents of a ``config.h`` file from the defines and includes
set in conf.env.define_key / conf.env.include_key. No include guards are added.
A prelude will be added from the variable env.WAF_CONFIG_H_PRELUDE if provided. This
can be used to insert complex macros or include guards::
def configure(conf):
conf.env.WAF_CONFIG_H_PRELUDE = '#include <unistd.h>\\n'
conf.write_config_header('config.h')
:param defines: write the defines values
:type defines: bool
:param headers: write the headers
:param headers: write include entries for each element in self.env.INCKEYS
:type headers: bool
:type define_prefix: string
:param define_prefix: prefix all the defines with a particular prefix
......@@ -908,6 +931,10 @@ def get_config_header(self, defines=True, headers=False, define_prefix=''):
:rtype: string
"""
lst = []
if self.env.WAF_CONFIG_H_PRELUDE:
lst.append(self.env.WAF_CONFIG_H_PRELUDE)
if headers:
for x in self.env[INCKEYS]:
lst.append('#include <%s>' % x)
......@@ -931,24 +958,24 @@ def cc_add_flags(conf):
"""
Add CFLAGS / CPPFLAGS from os.environ to conf.env
"""
conf.add_os_flags('CPPFLAGS', 'CFLAGS')
conf.add_os_flags('CFLAGS')
conf.add_os_flags('CPPFLAGS', dup=False)
conf.add_os_flags('CFLAGS', dup=False)
@conf
def cxx_add_flags(conf):
"""
Add CXXFLAGS / CPPFLAGS from os.environ to conf.env
"""
conf.add_os_flags('CPPFLAGS', 'CXXFLAGS')
conf.add_os_flags('CXXFLAGS')
conf.add_os_flags('CPPFLAGS', dup=False)
conf.add_os_flags('CXXFLAGS', dup=False)
@conf
def link_add_flags(conf):
"""
Add LINKFLAGS / LDFLAGS from os.environ to conf.env
"""
conf.add_os_flags('LINKFLAGS')
conf.add_os_flags('LDFLAGS')