summaryrefslogtreecommitdiff
path: root/waflib
diff options
context:
space:
mode:
authorKarl Linden <karl.j.linden@gmail.com>2015-09-26 13:27:35 +0200
committerKarl Linden <karl.j.linden@gmail.com>2015-09-26 13:27:35 +0200
commit8b8be738805ae1c5fe3688a49fd696a9f080b59e (patch)
tree956cef75f28fb0d271585f9f99054f60917b5aac /waflib
parenta3ad1ff94bf83868b07d70d596fce76f8f57f334 (diff)
downloadjack2-8b8be738805ae1c5fe3688a49fd696a9f080b59e.tar.gz
Update waf to 1.8.14
Diffstat (limited to 'waflib')
-rw-r--r--waflib/Build.py1
-rw-r--r--waflib/ConfigSet.py1
-rw-r--r--waflib/Configure.py26
-rw-r--r--waflib/Context.py106
-rw-r--r--waflib/Logs.py5
-rw-r--r--waflib/Options.py4
-rw-r--r--waflib/Scripting.py31
-rw-r--r--waflib/Task.py6
-rw-r--r--waflib/TaskGen.py6
-rw-r--r--waflib/Tools/c_aliases.py24
-rw-r--r--[-rwxr-xr-x]waflib/Tools/c_config.py89
-rw-r--r--waflib/Tools/c_osx.py32
-rw-r--r--waflib/Tools/ccroot.py28
-rw-r--r--waflib/Tools/clang.py1
-rw-r--r--waflib/Tools/clangxx.py1
-rw-r--r--waflib/Tools/errcheck.py2
-rw-r--r--waflib/Tools/gcc.py2
-rw-r--r--waflib/Tools/gxx.py2
-rw-r--r--waflib/Tools/msvc.py188
-rw-r--r--waflib/Tools/suncc.py4
-rw-r--r--waflib/Tools/suncxx.py3
-rw-r--r--waflib/ansiterm.py2
-rw-r--r--waflib/extras/lru_cache.py98
23 files changed, 407 insertions, 255 deletions
diff --git a/waflib/Build.py b/waflib/Build.py
index fdd59fb0..154e5c8c 100644
--- a/waflib/Build.py
+++ b/waflib/Build.py
@@ -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):
"""
diff --git a/waflib/ConfigSet.py b/waflib/ConfigSet.py
index de0c3aee..2fac2166 100644
--- a/waflib/ConfigSet.py
+++ b/waflib/ConfigSet.py
@@ -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):
"""
diff --git a/waflib/Configure.py b/waflib/Configure.py
index 1433336d..88468d23 100644
--- a/waflib/Configure.py
+++ b/waflib/Configure.py
@@ -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):
diff --git a/waflib/Context.py b/waflib/Context.py
index cb5e59b8..70cef85c 100644
--- a/waflib/Context.py
+++ b/waflib/Context.py
@@ -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
diff --git a/waflib/Logs.py b/waflib/Logs.py
index a8807199..8dd2af92 100644
--- a/waflib/Logs.py
+++ b/waflib/Logs.py
@@ -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',
diff --git a/waflib/Options.py b/waflib/Options.py
index ad6a44ff..f11fe3e3 100644
--- a/waflib/Options.py
+++ b/waflib/Options.py
@@ -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':
diff --git a/waflib/Scripting.py b/waflib/Scripting.py
index 4a78557c..832e3573 100644
--- a/waflib/Scripting.py
+++ b/waflib/Scripting.py
@@ -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):
"""
diff --git a/waflib/Task.py b/waflib/Task.py
index b70532e5..326ac303 100644
--- a/waflib/Task.py
+++ b/waflib/Task.py
@@ -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`)"""
diff --git a/waflib/TaskGen.py b/waflib/TaskGen.py
index b1110080..44aa25d5 100644
--- a/waflib/TaskGen.py
+++ b/waflib/TaskGen.py
@@ -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)
diff --git a/waflib/Tools/c_aliases.py b/waflib/Tools/c_aliases.py
index 65677801..4bb6352e 100644
--- a/waflib/Tools/c_aliases.py
+++ b/waflib/Tools/c_aliases.py
@@ -1,11 +1,11 @@
#!/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):
diff --git a/waflib/Tools/c_config.py b/waflib/Tools/c_config.py
index e9c22204..14243cd8 100755..100644
--- a/waflib/Tools/c_config.py
+++ b/waflib/Tools/c_config.py
@@ -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')
+ conf.add_os_flags('LINKFLAGS', dup=False)
+ conf.add_os_flags('LDFLAGS', dup=False)
@conf
def cc_load_tools(conf):
@@ -978,15 +1005,10 @@ def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
cmd = cc + ['-dM', '-E', '-']
env = conf.env.env or None
try:
- p = Utils.subprocess.Popen(cmd, stdin=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=env)
- p.stdin.write('\n'.encode())
- out = p.communicate()[0]
+ out, err = conf.cmd_and_log(cmd, output=0, input='\n'.encode(), env=env)
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 gcc:
if out.find('__INTEL_COMPILER') >= 0:
conf.fatal('The intel compiler pretends to be gcc')
@@ -999,7 +1021,7 @@ def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
if clang and out.find('__clang__') < 0:
conf.fatal('Not clang/clang++')
if not clang and out.find('__clang__') >= 0:
- conf.fatal('Could not find g++, if renamed try eg: CXX=g++48 waf configure')
+ conf.fatal('Could not find gcc/g++ (only Clang), if renamed try eg: CC=gcc48 CXX=g++48 waf configure')
k = {}
if icc or gcc or clang:
@@ -1014,9 +1036,6 @@ def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
def isD(var):
return var in k
- def isT(var):
- return var in k and k[var] != '0'
-
# Some documentation is available at http://predef.sourceforge.net
# The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
if not conf.env.DEST_OS:
@@ -1053,17 +1072,11 @@ def get_cc_version(conf, cc, gcc=False, icc=False, clang=False):
ver = k['__INTEL_COMPILER']
conf.env['CC_VERSION'] = (ver[:-2], ver[-2], ver[-1])
else:
- if isD('__clang__'):
- try:
- conf.env['CC_VERSION'] = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__'])
- except KeyError:
- # Some versions of OSX have a faux-gcc "clang" without clang version defines
- conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
+ if isD('__clang__') and isD('__clang_major__'):
+ conf.env['CC_VERSION'] = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__'])
else:
- try:
- conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
- except KeyError:
- conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], 0)
+ # older clang versions and gcc
+ conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k.get('__GNUC_PATCHLEVEL__', '0'))
return k
@conf
@@ -1165,6 +1178,7 @@ def multicheck(self, *k, **kw):
self.keep = False
self.returned_tasks = []
self.task_sigs = {}
+ self.progress_bar = 0
def total(self):
return len(tasks)
def to_log(self, *k, **kw):
@@ -1195,10 +1209,17 @@ def multicheck(self, *k, **kw):
for x in tasks:
x.logger.memhandler.flush()
+ if p.error:
+ for x in p.error:
+ if getattr(x, 'err_msg', None):
+ self.to_log(x.err_msg)
+ self.end_msg('fail', color='RED')
+ raise Errors.WafError('There is an error in the library, read config.log for more information')
+
for x in tasks:
if x.hasrun != Task.SUCCESS:
self.end_msg(kw.get('errmsg', 'no'), color='YELLOW', **kw)
- self.fatal(kw.get('fatalmsg', None) or 'One of the tests has failed, see the config.log for more information')
+ self.fatal(kw.get('fatalmsg', None) or 'One of the tests has failed, read config.log for more information')
self.end_msg('ok', **kw)
diff --git a/waflib/Tools/c_osx.py b/waflib/Tools/c_osx.py
index a2f62412..2b3c6474 100644
--- a/waflib/Tools/c_osx.py
+++ b/waflib/Tools/c_osx.py
@@ -24,7 +24,7 @@ app_info = '''
<key>NOTE</key>
<string>THIS IS A GENERATED FILE, DO NOT MODIFY</string>
<key>CFBundleExecutable</key>
- <string>%s</string>
+ <string>{app_name}</string>
</dict>
</plist>
'''
@@ -71,7 +71,7 @@ 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)
+ bld.shlib(source='a.c', target='foo', mac_app=True)
To force *all* executables to be transformed into Mac applications::
@@ -91,7 +91,22 @@ def create_task_macapp(self):
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_files', None):
+ # this only accepts files; they will be installed as seen from mac_files_root
+ mac_files_root = getattr(self, 'mac_files_root', None)
+ if isinstance(mac_files_root, str):
+ mac_files_root = self.path.find_node(mac_files_root)
+ if not mac_files_root:
+ self.bld.fatal('Invalid mac_files_root %r' % self.mac_files_root)
+ res_dir = n1.parent.parent.make_node('Resources')
+ inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Resources' % name
+ for node in self.to_nodes(self.mac_files):
+ relpath = node.path_from(mac_files_root or node.parent)
+ tsk = self.create_task('macapp', node, res_dir.make_node(relpath))
+ self.bld.install_as(os.path.join(inst_to, relpath), node)
+
if getattr(self, 'mac_resources', None):
+ # TODO remove in waf 1.9
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):
@@ -127,6 +142,14 @@ def create_task_macplist(self):
dir = self.create_bundle_dirs(name, out)
n1 = dir.find_or_declare(['Contents', 'Info.plist'])
self.plisttask = plisttask = self.create_task('macplist', [], n1)
+ plisttask.context = {
+ 'app_name': self.link_task.outputs[0].name,
+ 'env': self.env
+ }
+
+ plist_ctx = getattr(self, 'plist_context', None)
+ if (plist_ctx):
+ plisttask.context.update(plist_ctx)
if getattr(self, 'mac_plist', False):
node = self.path.find_resource(self.mac_plist)
@@ -135,7 +158,7 @@ def create_task_macplist(self):
else:
plisttask.code = self.mac_plist
else:
- plisttask.code = app_info % self.link_task.outputs[0].name
+ plisttask.code = app_info
inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/' % name
self.bld.install_files(inst_to, n1)
@@ -184,5 +207,6 @@ class macplist(Task.Task):
txt = self.code
else:
txt = self.inputs[0].read()
+ context = getattr(self, 'context', {})
+ txt = txt.format(**context)
self.outputs[0].write(txt)
-
diff --git a/waflib/Tools/ccroot.py b/waflib/Tools/ccroot.py
index 05484e30..363d18d1 100644
--- a/waflib/Tools/ccroot.py
+++ b/waflib/Tools/ccroot.py
@@ -489,10 +489,19 @@ def apply_vnum(self):
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:
+ In this example on Linux platform, ``libfoo.so`` is installed as ``libfoo.so.14.15.16``, and the following symbolic links are created:
- * ``libfoo.so → libfoo.so.1.2.3``
- * ``libfoo.so.1 → libfoo.so.1.2.3``
+ * ``libfoo.so → libfoo.so.14.15.16``
+ * ``libfoo.so.14 → libfoo.so.14.15.16``
+
+ By default, the library will be assigned SONAME ``libfoo.so.14``, effectively declaring ABI compatibility between all minor and patch releases for the major version of the library. When necessary, the compatibility can be explicitly defined using `cnum` parameter:
+
+ def build(bld):
+ bld.shlib(source='a.c', target='foo', vnum='14.15.16', cnum='14.15')
+
+ In this case, the assigned SONAME will be ``libfoo.so.14.15`` with ABI compatibility only between path releases for a specific major and minor version of the library.
+
+ On OS X platform, install-name parameter will follow the above logic for SONAME with exception that it also specifies an absolute path (based on install_path) of the library.
"""
if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
return
@@ -503,13 +512,18 @@ def apply_vnum(self):
nums = self.vnum.split('.')
node = link.outputs[0]
+ cnum = getattr(self, 'cnum', str(nums[0]))
+ cnums = cnum.split('.')
+ if len(cnums)>len(nums) or nums[0:len(cnums)] != cnums:
+ raise Errors.WafError('invalid compatibility version %s' % cnum)
+
libname = node.name
if libname.endswith('.dylib'):
name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
- name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
+ name2 = libname.replace('.dylib', '.%s.dylib' % cnum)
else:
name3 = libname + '.' + self.vnum
- name2 = libname + '.' + nums[0]
+ name2 = libname + '.' + cnum
# add the so name for the ld linker - to disable, just unset env.SONAME_ST
if self.env.SONAME_ST:
@@ -548,8 +562,10 @@ def apply_vnum(self):
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)
+ path = os.path.join(p, name2)
self.env.append_value('LINKFLAGS', ['-install_name', path])
+ self.env.append_value('LINKFLAGS', '-Wl,-compatibility_version,%s' % cnum)
+ self.env.append_value('LINKFLAGS', '-Wl,-current_version,%s' % self.vnum)
class vnum(Task.Task):
"""
diff --git a/waflib/Tools/clang.py b/waflib/Tools/clang.py
index 999c604c..0740e00b 100644
--- a/waflib/Tools/clang.py
+++ b/waflib/Tools/clang.py
@@ -21,6 +21,7 @@ def find_clang(conf):
def configure(conf):
conf.find_clang()
+ conf.find_program(['llvm-ar', 'ar'], var='AR')
conf.find_ar()
conf.gcc_common_flags()
conf.gcc_modifier_platform()
diff --git a/waflib/Tools/clangxx.py b/waflib/Tools/clangxx.py
index c8d34a71..b52fc352 100644
--- a/waflib/Tools/clangxx.py
+++ b/waflib/Tools/clangxx.py
@@ -21,6 +21,7 @@ def find_clangxx(conf):
def configure(conf):
conf.find_clangxx()
+ conf.find_program(['llvm-ar', 'ar'], var='AR')
conf.find_ar()
conf.gxx_common_flags()
conf.gxx_modifier_platform()
diff --git a/waflib/Tools/errcheck.py b/waflib/Tools/errcheck.py
index 9ac0cafe..14ce28fb 100644
--- a/waflib/Tools/errcheck.py
+++ b/waflib/Tools/errcheck.py
@@ -64,7 +64,7 @@ def check_same_targets(self):
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')
+ Logs.error('* Several tasks use the same identifier. Please check the information on\n https://waf.io/apidocs/Task.html?highlight=uid#waflib.Task.Task.uid')
for tsk in v:
Logs.error(' - object %r (%r) defined in %r' % (tsk.__class__.__name__, tsk, tsk.generator))
diff --git a/waflib/Tools/gcc.py b/waflib/Tools/gcc.py
index 8cb954f8..741a2e3f 100644
--- a/waflib/Tools/gcc.py
+++ b/waflib/Tools/gcc.py
@@ -97,7 +97,7 @@ 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['LINKFLAGS_cshlib'] = ['-dynamiclib']
v['cshlib_PATTERN'] = 'lib%s.dylib'
v['FRAMEWORKPATH_ST'] = '-F%s'
v['FRAMEWORK_ST'] = ['-framework']
diff --git a/waflib/Tools/gxx.py b/waflib/Tools/gxx.py
index 55bf2a70..4c89273b 100644
--- a/waflib/Tools/gxx.py
+++ b/waflib/Tools/gxx.py
@@ -97,7 +97,7 @@ 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['LINKFLAGS_cxxshlib'] = ['-dynamiclib']
v['cxxshlib_PATTERN'] = 'lib%s.dylib'
v['FRAMEWORKPATH_ST'] = '-F%s'
v['FRAMEWORK_ST'] = ['-framework']
diff --git a/waflib/Tools/msvc.py b/waflib/Tools/msvc.py
index 97323247..c220f3f9 100644
--- a/waflib/Tools/msvc.py
+++ b/waflib/Tools/msvc.py
@@ -30,6 +30,10 @@ or::
Platforms and targets will be tested in the order they appear;
the first good configuration will be used.
+
+To skip testing all the configurations that are not used, use the ``--msvc_lazy_autodetect`` option
+or set ``conf.env['MSVC_LAZY_AUTODETECT']=True``.
+
Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64, x86_arm, amd64_x86, amd64_arm
Compilers supported:
@@ -90,8 +94,18 @@ all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'),
def options(opt):
opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='')
opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='')
+ opt.add_option('--msvc_lazy_autodetect', action='store_true', help = 'lazily check msvc target environments')
def setup_msvc(conf, versions, arch = False):
+ """
+ Checks installed compilers and targets and returns the first combination from the user's
+ options, env, or the global supported lists that checks.
+
+ :param versions: A list of tuples of all installed compilers and available targets.
+ :param arch: Whether to return the target architecture.
+ :return: the compiler, revision, path, include dirs, library paths, and (optionally) target architecture
+ :rtype: tuple of strings
+ """
platforms = getattr(Options.options, 'msvc_targets', '').split(',')
if platforms == ['']:
platforms=Utils.to_list(conf.env['MSVC_TARGETS']) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
@@ -102,15 +116,20 @@ def setup_msvc(conf, versions, arch = False):
for version in desired_versions:
try:
- targets = dict(versiondict [version])
+ targets = dict(versiondict[version])
for target in platforms:
try:
- arch,(p1,p2,p3) = targets[target]
- compiler,revision = version.rsplit(' ', 1)
- if arch:
- return compiler,revision,p1,p2,p3,arch
+ try:
+ realtarget,(p1,p2,p3) = targets[target]
+ except conf.errors.ConfigurationError:
+ # lazytup target evaluation errors
+ del(targets[target])
else:
- return compiler,revision,p1,p2,p3
+ compiler,revision = version.rsplit(' ', 1)
+ if arch:
+ return compiler,revision,p1,p2,p3,realtarget
+ else:
+ return compiler,revision,p1,p2,p3
except KeyError: continue
except KeyError: continue
conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)')
@@ -118,13 +137,14 @@ def setup_msvc(conf, versions, arch = False):
@conf
def get_msvc_version(conf, compiler, version, target, vcvars):
"""
- Create a bat file to obtain the location of the libraries
-
- :param compiler: ?
- :param version: ?
- :target: ?
- :vcvars: ?
- :return: the location of msvc, the location of include dirs, and the library paths
+ Checks that an installed compiler actually runs and uses vcvars to obtain the
+ environment needed by the compiler.
+
+ :param compiler: compiler type, for looking up the executable name
+ :param version: compiler version, for debugging only
+ :param target: target architecture
+ :param vcvars: batch file to run to check the environment
+ :return: the location of the compiler executable, the location of include dirs, and the library paths
:rtype: tuple of strings
"""
debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
@@ -219,7 +239,7 @@ def gather_wsdk_versions(conf, versions):
targets = []
for target,arch in all_msvc_platforms:
try:
- targets.append((target, (arch, conf.get_msvc_version('wsdk', version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')))))
+ targets.append((target, (arch, get_compiler_env(conf, 'wsdk', version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')))))
except conf.errors.ConfigurationError:
pass
versions.append(('wsdk ' + version[1:], targets))
@@ -262,12 +282,12 @@ def gather_wince_supported_platforms():
path,device = os.path.split(path)
if not device:
path,device = os.path.split(path)
+ platforms = []
for arch,compiler in all_wince_platforms:
- platforms = []
if os.path.isdir(os.path.join(path, device, 'Lib', arch)):
platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch)))
- if platforms:
- supported_wince_platforms.append((device, platforms))
+ if platforms:
+ supported_wince_platforms.append((device, platforms))
return supported_wince_platforms
def gather_msvc_detected_versions():
@@ -304,6 +324,65 @@ def gather_msvc_detected_versions():
detected_versions.sort(key = fun)
return detected_versions
+def get_compiler_env(conf, compiler, version, bat_target, bat, select=None):
+ """
+ Gets the compiler environment variables as a tuple. Evaluation is eager by default.
+ If set to lazy with ``--msvc_lazy_autodetect`` or ``env.MSVC_LAZY_AUTODETECT``
+ the environment is evaluated when the tuple is destructured or iterated. This means
+ destructuring can throw :py:class:`conf.errors.ConfigurationError`.
+
+ :param conf: configuration context to use to eventually get the version environment
+ :param compiler: compiler name
+ :param version: compiler version number
+ :param bat: path to the batch file to run
+ :param select: optional function to take the realized environment variables tup and map it (e.g. to combine other constant paths)
+ """
+ lazy = getattr(Options.options, 'msvc_lazy_autodetect', False) or conf.env['MSVC_LAZY_AUTODETECT']
+
+ def msvc_thunk():
+ vs = conf.get_msvc_version(compiler, version, bat_target, bat)
+ if select:
+ return select(vs)
+ else:
+ return vs
+ return lazytup(msvc_thunk, lazy, ([], [], []))
+
+class lazytup(object):
+ """
+ A tuple that evaluates its elements from a function when iterated or destructured.
+
+ :param fn: thunk to evaluate the tuple on demand
+ :param lazy: whether to delay evaluation or evaluate in the constructor
+ :param default: optional default for :py:func:`repr` if it should not evaluate
+ """
+ def __init__(self, fn, lazy=True, default=None):
+ self.fn = fn
+ self.default = default
+ if not lazy:
+ self.evaluate()
+ def __len__(self):
+ self.evaluate()
+ return len(self.value)
+ def __iter__(self):
+ self.evaluate()
+ for i, v in enumerate(self.value):
+ yield v
+ def __getitem__(self, i):
+ self.evaluate()
+ return self.value[i]
+ def __repr__(self):
+ if hasattr(self, 'value'):
+ return repr(self.value)
+ elif self.default:
+ return repr(self.default)
+ else:
+ self.evaluate()
+ return repr(self.value)
+ def evaluate(self):
+ if hasattr(self, 'value'):
+ return
+ self.value = self.fn()
+
@conf
def gather_msvc_targets(conf, versions, version, vc_path):
#Looking for normal MSVC compilers!
@@ -311,17 +390,17 @@ def gather_msvc_targets(conf, versions, version, vc_path):
if os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
for target,realtarget in all_msvc_platforms[::-1]:
try:
- targets.append((target, (realtarget, conf.get_msvc_version('msvc', version, target, os.path.join(vc_path, 'vcvarsall.bat')))))
+ targets.append((target, (realtarget, get_compiler_env(conf, 'msvc', version, target, os.path.join(vc_path, 'vcvarsall.bat')))))
except conf.errors.ConfigurationError:
pass
elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):
try:
- targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')))))
+ targets.append(('x86', ('x86', get_compiler_env(conf, 'msvc', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')))))
except conf.errors.ConfigurationError:
pass
elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):
try:
- targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')))))
+ targets.append(('x86', ('x86', get_compiler_env(conf, 'msvc', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')))))
except conf.errors.ConfigurationError:
pass
if targets:
@@ -336,15 +415,18 @@ def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_pla
winCEpath = os.path.join(vc_path, 'ce')
if not os.path.isdir(winCEpath):
continue
- try:
- common_bindirs,_1,_2 = conf.get_msvc_version('msvc', version, 'x86', vsvars)
- except conf.errors.ConfigurationError:
- continue
+
if os.path.isdir(os.path.join(winCEpath, 'lib', platform)):
- bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)] + common_bindirs
+ bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)]
incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include]
libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib]
- cetargets.append((platform, (platform, (bindirs,incdirs,libdirs))))
+ def combine_common(compiler_env):
+ (common_bindirs,_1,_2) = compiler_env
+ return (bindirs + common_bindirs, incdirs, libdirs)
+ try:
+ cetargets.append((platform, (platform, get_compiler_env(conf, 'msvc', version, 'x86', vsvars, combine_common))))
+ except conf.errors.ConfigurationError:
+ continue
if cetargets:
versions.append((device + ' ' + version, cetargets))
@@ -354,8 +436,8 @@ def gather_winphone_targets(conf, versions, version, vc_path, vsvars):
targets = []
for target,realtarget in all_msvc_platforms[::-1]:
try:
- targets.append((target, (realtarget, conf.get_msvc_version('winphone', version, target, vsvars))))
- except conf.errors.ConfigurationError as e:
+ targets.append((target, (realtarget, get_compiler_env(conf, 'winphone', version, target, vsvars))))
+ except conf.errors.ConfigurationError:
pass
if targets:
versions.append(('winphone '+ version, targets))
@@ -382,9 +464,14 @@ def gather_msvc_versions(conf, versions):
if wince_supported_platforms and os.path.isfile(vsvars):
conf.gather_wince_targets(versions, version, vc_path, vsvars, wince_supported_platforms)
+ # WP80 works with 11.0Exp and 11.0, both of which resolve to the same vc_path.
+ # Stop after one is found.
+ for version,vc_path in vc_paths:
+ vs_path = os.path.dirname(vc_path)
vsvars = os.path.join(vs_path, 'VC', 'WPSDK', 'WP80', 'vcvarsphoneall.bat')
if os.path.isfile(vsvars):
conf.gather_winphone_targets(versions, '8.0', vc_path, vsvars)
+ break
for version,vc_path in vc_paths:
vs_path = os.path.dirname(vc_path)
@@ -426,7 +513,7 @@ def gather_icl_versions(conf, versions):
batch_file=os.path.join(path,'bin','iclvars.bat')
if os.path.isfile(batch_file):
try:
- targets.append((target,(arch,conf.get_msvc_version('intel',version,target,batch_file))))
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
except conf.errors.ConfigurationError:
pass
except WindowsError:
@@ -438,7 +525,7 @@ def gather_icl_versions(conf, versions):
batch_file=os.path.join(path,'bin','iclvars.bat')
if os.path.isfile(batch_file):
try:
- targets.append((target, (arch, conf.get_msvc_version('intel', version, target, batch_file))))
+ targets.append((target, (arch, get_compiler_env(conf, 'intel', version, target, batch_file))))
except conf.errors.ConfigurationError:
pass
except WindowsError:
@@ -490,8 +577,8 @@ def gather_intel_composer_versions(conf, versions):
batch_file=os.path.join(path,'bin','iclvars.bat')
if os.path.isfile(batch_file):
try:
- targets.append((target,(arch,conf.get_msvc_version('intel',version,target,batch_file))))
- except conf.errors.ConfigurationError as e:
+ targets.append((target,(arch,get_compiler_env(conf,'intel',version,target,batch_file))))
+ except conf.errors.ConfigurationError:
pass
# The intel compilervar_arch.bat is broken when used with Visual Studio Express 2012
# http://software.intel.com/en-us/forums/topic/328487
@@ -516,19 +603,36 @@ def gather_intel_composer_versions(conf, versions):
versions.append(('intel ' + major, targets))
@conf
-def get_msvc_versions(conf):
+def get_msvc_versions(conf, eval_and_save=True):
"""
:return: list of compilers installed
:rtype: list of string
"""
- if not conf.env['MSVC_INSTALLED_VERSIONS']:
- lst = []
- conf.gather_icl_versions(lst)
- conf.gather_intel_composer_versions(lst)
- conf.gather_wsdk_versions(lst)
- conf.gather_msvc_versions(lst)
+ if conf.env['MSVC_INSTALLED_VERSIONS']:
+ return conf.env['MSVC_INSTALLED_VERSIONS']
+
+ # Gather all the compiler versions and targets. This phase can be lazy
+ # per lazy detection settings.
+ lst = []
+ conf.gather_icl_versions(lst)
+ conf.gather_intel_composer_versions(lst)
+ conf.gather_wsdk_versions(lst)
+ conf.gather_msvc_versions(lst)
+
+ # Override lazy detection by evaluating after the fact.
+ if eval_and_save:
+ def checked_target(t):
+ target,(arch,paths) = t
+ try:
+ paths.evaluate()
+ except conf.errors.ConfigurationError:
+ return None
+ else:
+ return t
+ lst = [(version, list(filter(checked_target, targets))) for version, targets in lst]
conf.env['MSVC_INSTALLED_VERSIONS'] = lst
- return conf.env['MSVC_INSTALLED_VERSIONS']
+
+ return lst
@conf
def print_all_msvc_detected(conf):
@@ -542,7 +646,9 @@ def print_all_msvc_detected(conf):
@conf
def detect_msvc(conf, arch = False):
- versions = get_msvc_versions(conf)
+ # Save installed versions only if lazy detection is disabled.
+ lazy_detect = getattr(Options.options, 'msvc_lazy_autodetect', False) or conf.env['MSVC_LAZY_AUTODETECT']
+ versions = get_msvc_versions(conf, not lazy_detect)
return setup_msvc(conf, versions, arch)
@conf
diff --git a/waflib/Tools/suncc.py b/waflib/Tools/suncc.py
index e705c328..4909854e 100644
--- a/waflib/Tools/suncc.py
+++ b/waflib/Tools/suncc.py
@@ -3,7 +3,6 @@
# Thomas Nagy, 2006-2010 (ita)
# Ralf Habacker, 2006 (rh)
-from waflib import Utils
from waflib.Tools import ccroot, ar
from waflib.Configure import conf
@@ -53,7 +52,7 @@ def scc_common_flags(conf):
v['cprogram_PATTERN'] = '%s'
# shared library
- v['CFLAGS_cshlib'] = ['-Kpic', '-DPIC']
+ v['CFLAGS_cshlib'] = ['-xcode=pic32', '-DPIC']
v['LINKFLAGS_cshlib'] = ['-G']
v['cshlib_PATTERN'] = 'lib%s.so'
@@ -68,4 +67,3 @@ def configure(conf):
conf.cc_load_tools()
conf.cc_add_flags()
conf.link_add_flags()
-
diff --git a/waflib/Tools/suncxx.py b/waflib/Tools/suncxx.py
index 01b3f8d2..5a04b483 100644
--- a/waflib/Tools/suncxx.py
+++ b/waflib/Tools/suncxx.py
@@ -3,7 +3,6 @@
# Thomas Nagy, 2006-2010 (ita)
# Ralf Habacker, 2006 (rh)
-from waflib import Utils
from waflib.Tools import ccroot, ar
from waflib.Configure import conf
@@ -51,7 +50,7 @@ def sxx_common_flags(conf):
v['cxxprogram_PATTERN'] = '%s'
# shared library
- v['CXXFLAGS_cxxshlib'] = ['-Kpic', '-DPIC']
+ v['CXXFLAGS_cxxshlib'] = ['-xcode=pic32', '-DPIC']
v['LINKFLAGS_cxxshlib'] = ['-G']
v['cxxshlib_PATTERN'] = 'lib%s.so'
diff --git a/waflib/ansiterm.py b/waflib/ansiterm.py
index e7a4ce75..64fa1407 100644
--- a/waflib/ansiterm.py
+++ b/waflib/ansiterm.py
@@ -284,7 +284,7 @@ else:
wlock.release()
def writeconsole(self, txt):
- chars_written = c_int()
+ chars_written = c_ulong()
writeconsole = windll.kernel32.WriteConsoleA
if isinstance(txt, _type):
writeconsole = windll.kernel32.WriteConsoleW
diff --git a/waflib/extras/lru_cache.py b/waflib/extras/lru_cache.py
deleted file mode 100644
index 2bc96442..00000000
--- a/waflib/extras/lru_cache.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#! /usr/bin/env python
-# encoding: utf-8
-# Thomas Nagy 2011
-
-import os, shutil, re
-from waflib import Options, Build, Logs
-
-"""
-Apply a least recently used policy to the Waf cache.
-
-For performance reasons, it is called after the build is complete.
-
-We assume that the the folders are written atomically
-
-Do export WAFCACHE=/tmp/foo_xyz where xyz represents the cache size in bytes
-If missing, the default cache size will be set to 10GB
-"""
-
-re_num = re.compile('[a-zA-Z_-]+(\d+)')
-
-CACHESIZE = 10*1024*1024*1024 # in bytes
-CLEANRATIO = 0.8
-DIRSIZE = 4096
-
-def compile(self):
- if Options.cache_global and not Options.options.nocache:
- try:
- os.makedirs(Options.cache_global)
- except:
- pass
-
- try:
- self.raw_compile()
- finally:
- if Options.cache_global and not Options.options.nocache:
- self.sweep()
-
-def sweep(self):
- global CACHESIZE
- CACHEDIR = Options.cache_global
-
- # get the cache max size from the WAFCACHE filename
- re_num = re.compile('[a-zA-Z_]+(\d+)')
- val = re_num.sub('\\1', os.path.basename(Options.cache_global))
- try:
- CACHESIZE = int(val)
- except:
- pass
-
- # map folder names to timestamps
- flist = {}
- for x in os.listdir(CACHEDIR):
- j = os.path.join(CACHEDIR, x)
- if os.path.isdir(j) and len(x) == 64: # dir names are md5 hexdigests
- flist[x] = [os.stat(j).st_mtime, 0]
-
- for (x, v) in flist.items():
- cnt = DIRSIZE # each entry takes 4kB
- d = os.path.join(CACHEDIR, x)
- for k in os.listdir(d):
- cnt += os.stat(os.path.join(d, k)).st_size
- flist[x][1] = cnt
-
- total = sum([x[1] for x in flist.values()])
- Logs.debug('lru: Cache size is %r' % total)
-
- if total >= CACHESIZE:
- Logs.debug('lru: Trimming the cache since %r > %r' % (total, CACHESIZE))
-
- # make a list to sort the folders by timestamp
- lst = [(p, v[0], v[1]) for (p, v) in flist.items()]
- lst.sort(key=lambda x: x[1]) # sort by timestamp
- lst.reverse()
-
- while total >= CACHESIZE * CLEANRATIO:
- (k, t, s) = lst.pop()
- p = os.path.join(CACHEDIR, k)
- v = p + '.del'
- try:
- os.rename(p, v)
- except:
- # someone already did it
- pass
- else:
- try:
- shutil.rmtree(v)
- except:
- # this should not happen, but who knows?
- Logs.warn('If you ever see this message, report it (%r)' % v)
- total -= s
- del flist[k]
-
- Logs.debug('lru: Total at the end %r' % total)
-
-Build.BuildContext.raw_compile = Build.BuildContext.compile
-Build.BuildContext.compile = compile
-Build.BuildContext.sweep = sweep
-