Anonymous avatar Anonymous committed 405a203 Merge

sync with waf-master

Comments (0)

Files changed (24)

+NEW IN WAF 1.7.0
+----------------
+* Do not load the compat15 tool by default
+* Minor API cleanup
+* Require Python >= 2.4
+
 NEW IN WAF 1.6.11
 -----------------
-* Apply the chmod attribute to the versioned libraries (vnum)
+* Enable custom variables for the boost detection #1089
+* Disable the config test execution when detecting boost #1090
+* Process moc classes in .cpp files by default #1095
+* Apply the chmod attribute to the versioned libraries (vnum) #1097
+* Fixed the python detection on OSX #1098
+* Changed the win32 color settings for Windows 7 #1099
+* Set the default fortran linker for ifort to xiar #1104
 
 NEW IN WAF 1.6.10
 -----------------

demos/fortran/wscript

 out = 'build'
 
 def options(opt):
+	opt.load('compiler_fc')
 	opt.load('compiler_c')
-	opt.load('compiler_fc')
 	opt.recurse('typemap')
 
 def configure(conf):
+	conf.load('compiler_fc')
 	conf.load('compiler_c')
-	conf.load('compiler_fc')
 	if conf.env.FC_NAME == 'IFORT':
 		conf.env['FCFLAGS'] = ['-warn']
 	elif conf.env.FC_NAME == 'GFORTRAN':

demos/pch/wscript

 from waflib.Task import Task
 from waflib.Tools import c_preproc
 
-#@feature('cxx') <- python >= 2.4
-#@after('apply_link')
+@feature('cxx')
+@after('apply_link')
 def process_pch(self):
 	if getattr(self, 'pch', ''):
 		nodes = self.to_nodes(self.pch)
 		for x in nodes:
-			self.create_task('gchx', x, x.change_ext('.gch'))
-feature('cxx')(process_pch)
-after('apply_link')(process_pch)
+			self.create_task('gchx', x, x.change_ext('.h.gch'))
 
 class gchx(Task):
 	run_str = '${CXX} ${CXXFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}'
 	scan    = c_preproc.scan
 	ext_out = ['.h']
 	color   = 'BLUE'
+from waflib.Task import update_outputs
+update_outputs(gchx)
 
 #################################################
 # example below

demos/python/wscript

 	conf.check_python_version((2,4,2))
 	conf.check_python_headers()
 
+	conf.check_python_module('os')
+	conf.check_python_module('re', condition="ver > num(2,0,4) and ver <= num(2,3,0)")
 	try:
 		conf.check_python_module('pygccxml')
 	except conf.errors.ConfigurationError:
 
 import os, sys
 
-VERSION="1.6.10"
+VERSION="1.7.0"
 REVISION="x"
 INSTALL="x"
 C1='x'

waflib/Context.py

 import waflib.Node
 
 # the following 3 constants are updated on each new release (do not touch)
-HEXVERSION=0x1060a00
+HEXVERSION=0x1070000
 """Constant updated on new releases"""
 
-WAFVERSION="1.6.10"
+WAFVERSION="1.7.0"
 """Constant updated on new releases"""
 
 WAFREVISION="a7e69d6b81b04729804754c4d5214da063779a65"
 				ret = tsk.generator.bld.exec_command('touch foo.txt')
 				return ret
 
-		Do not confuse this method with :py:meth:`waflib.Context.Context.cmd_and_log` which is used to
-		return the standard output/error values.
+		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
 		Logs.debug('runner: %r' % cmd)
 		Logs.debug('runner_env: kw=%s' % kw)
 
+		if self.logger:
+			self.logger.info(cmd)
+
+		kw['stdout'] = kw['stderr'] = subprocess.PIPE
+
 		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 out:
+			if not isinstance(out, str):
+				out = out.decode(sys.stdout.encoding or 'iso8859-1')
+			sys.stdout.write(out)
 			if self.logger:
-				# warning: may deadlock with a lot of output (subprocess limitation)
+				self.logger.debug('out: %s' % out)
+		if err:
+			if not isinstance(err, str):
+				err = err.decode(sys.stdout.encoding or 'iso8859-1')
+			sys.stderr.write(err)
+			if self.logger:
+				self.logger.error('err: %s' % err)
 
-				self.logger.info(cmd)
-
-				kw['stdout'] = kw['stderr'] = subprocess.PIPE
-				p = subprocess.Popen(cmd, **kw)
-				(out, err) = p.communicate()
-				if out:
-					self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1'))
-				if err:
-					self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1'))
-				return p.returncode
-			else:
-				p = subprocess.Popen(cmd, **kw)
-				return p.wait()
-		except OSError:
-			return -1
+		return p.returncode
 
 	def cmd_and_log(self, cmd, **kw):
 		"""
 
 	* 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')
 
 		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
+		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
 
 		return ret
 
-	def find_nodes(self, find_dirs=True, find_files=True, match_fun=lambda x: True):
-		# FIXME not part of the stable API: find_node vs find_nodes? consistency with argument names on other functions?
-		x = """
-		Recursively finds nodes::
-
-			def configure(cnf):
-				cnf.find_nodes()
-
-		:param find_dirs: whether to return directories
-		:param find_files: whether to return files
-		:param match_fun: matching function, taking a node as parameter
-		:rtype generator
-		:return: a generator that iterates over all the requested files
-		"""
-		files = self.listdir()
-		for f in files:
-			node = self.make_node([f])
-			if os.path.isdir(node.abspath()):
-				if find_dirs and match_fun(node):
-					yield node
-				gen = node.find_nodes(find_dirs, find_files, match_fun)
-				for g in gen:
-					yield g
-			else:
-				if find_files and match_fun(node):
-					yield node
-
-
 	# --------------------------------------------------------------------------------
 	# the following methods require the source/build folders (bld.srcnode/bld.bldnode)
 	# using a subclass is a possibility, but is that really necessary?

File contents unchanged.

 
 	def run(self):
 		"""
-		Execute the task (executed by threads). Override in subclasses.
+		Called by threads to execute the tasks. The default is empty and meant to be overridden in subclasses.
+		It is a bad idea to create nodes in this method (so, no node.ant_glob)
 
 		:rtype: int
 		"""
 		:rtype: string
 		"""
 		msg = getattr(self, 'last_cmd', '')
+		name = getattr(self.generator, 'name', '')
 		if getattr(self, "err_msg", None):
 			return self.err_msg
 		elif not self.hasrun:
-			return 'task was not executed for some reason'
+			return 'task in %r was not executed for some reason: %r' % (name, self)
 		elif self.hasrun == CRASHED:
 			try:
-				return ' -> task failed (exit status %r): %r\n%r' % (self.err_code, self, msg)
+				return ' -> task in %r failed (exit status %r): %r\n%r' % (name, self.err_code, self, msg)
 			except AttributeError:
-				return ' -> task failed: %r\n%r' % (self, msg)
+				return ' -> task in %r failed: %r\n%r' % (name, self, msg)
 		elif self.hasrun == MISSING:
-			return ' -> missing files: %r\n%r' % (self, msg)
+			return ' -> missing files in %r: %r\n%r' % (name, self, msg)
 		else:
-			return 'invalid status %r' % self.hasrun
+			return 'invalid status for task in %r: %r' % (name, self.hasrun)
 
 	def colon(self, var1, var2):
 		"""

waflib/TaskGen.py

 			else:
 				tmp.append(a)
 
-		# TODO waf 1.7
-		#tmp.sort()
+		tmp.sort()
 
 		# topological sort
 		out = []
 	if getattr(self, 'cwd', None):
 		tsk.cwd = self.cwd
 
-	# TODO remove on_results in waf 1.7
-	if getattr(self, 'update_outputs', None) or getattr(self, 'on_results', None):
+	if getattr(self, 'update_outputs', None):
 		Task.update_outputs(cls)
 
 	if getattr(self, 'always', None):

waflib/Tools/c.py

 	ext_in  = ['.h'] # set the build order easily by using ext_out=['.h']
 	scan    = c_preproc.scan
 
-Task.classes['cc'] = cc = c # compat, remove in waf 1.7
-
 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}'

waflib/Tools/c_config.py

 C/C++/D configuration helpers
 """
 
-import os, imp, sys, re, shlex, shutil
-from waflib import Build, Utils, Configure, Task, Options, Logs, TaskGen, Errors, ConfigSet, Runner
-from waflib.TaskGen import before_method, after_method, feature
+import os, re, shlex, sys
+from waflib import Build, Utils, Task, Options, Logs, Errors, ConfigSet, Runner
+from waflib.TaskGen import after_method, feature
 from waflib.Configure import conf
 
 WAF_CONFIG_H   = 'config.h'
 '''
 """Code template for checking for types"""
 
-SNIP_CLASS = '''
-int main() {
-	if (
-}
-'''
-
 SNIP_EMPTY_PROGRAM = '''
 int main() {
 	return 0;
 	ret = None
 	try:
 		ret = self.exec_cfg(kw)
-	except self.errors.WafError as e:
+	except self.errors.WafError:
 		if 'errmsg' in kw:
 			self.end_msg(kw['errmsg'], 'YELLOW')
 		if Logs.verbose > 1:
 	if 'define_name' in kw:
 		# TODO simplify?
 		if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:
-			nm = kw['define_name']
 			if kw['execute'] and kw.get('define_ret', None) and isinstance(is_success, str):
 				self.define(kw['define_name'], is_success, quote=kw.get('quote', 1))
 			else:
 	ret = None
 	try:
 		ret = self.run_c_code(*k, **kw)
-	except self.errors.ConfigurationError as e:
+	except self.errors.ConfigurationError:
 		self.end_msg(kw['errmsg'], 'YELLOW')
 		if Logs.verbose > 1:
 			raise
 		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]
-	except:
+	except Exception:
 		conf.fatal('Could not determine the compiler version %r' % cmd)
 
 	if not isinstance(out, str):
-		out = out.decode(sys.stdout.encoding)
+		out = out.decode(sys.stdout.encoding or 'iso8859-1')
 
 	if gcc:
 		if out.find('__INTEL_COMPILER') >= 0:
 
 	k = {}
 	if icc or gcc:
-		out = out.split('\n')
+		out = out.splitlines()
 		for line in out:
 			lst = shlex.split(line)
 			if len(lst)>2:

waflib/Tools/ccroot.py

 					self.uselib.append(k)
 
 @taskgen_method
+def accept_node_to_link(self, node):
+	"""
+	PRIVATE INTERNAL USE ONLY
+	"""
+	return not x.name.endswith('.pdb')
+
+@taskgen_method
 def add_objects_from_tgen(self, tg):
-	# Not public yet, wait for waf 1.6.7 at least - the purpose of this is to add pdb files to the compiled
-	# tasks but not to the link tasks (to avoid errors)
+	"""
+	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:
 	else:
 		for tsk in getattr(tg, 'compiled_tasks', []):
 			for x in tsk.outputs:
-				if x.name.endswith('.o') or x.name.endswith('.obj'):
+				if self.accept_node_to_link(x):
 					link_task.inputs.append(x)
 
 @taskgen_method
 	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)
+

waflib/Tools/compiler_fc.py

 	"""
 	try: test_for_compiler = conf.options.check_fc
 	except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_fc')")
-	orig = conf.env
 	for compiler in test_for_compiler.split():
+		conf.env.stash()
+		conf.start_msg('Checking for %r (fortran compiler)' % compiler)
 		try:
-			conf.start_msg('Checking for %r (fortran compiler)' % compiler)
-			conf.env = orig.derive()
 			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']:
-				orig.table = conf.env.get_merged_dict()
-				conf.env = orig
 				conf.end_msg(conf.env.get_flat('FC'))
 				conf.env.COMPILER_FORTRAN = compiler
 				break

waflib/Tools/cxx.py

 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)
-TaskGen.extension('.cpp','.cc','.cxx','.C','.c++')(cxx_hook) # leave like this for python 2.3
 
 if not '.c' in TaskGen.task_gen.mappings:
 	TaskGen.task_gen.mappings['.c'] = TaskGen.task_gen.mappings['.cpp']

waflib/Tools/fc.py

 				for t in outs[k]:
 					tmp.extend(t.outputs)
 				a.dep_nodes.extend(tmp)
-
-				# old python versions
-				try:
-					a.dep_nodes.sort(key=lambda x: x.abspath())
-				except:
-					a.dep_nodes.sort(lambda x, y: cmp(x.abspath(), y.abspath()))
+				a.dep_nodes.sort(key=lambda x: x.abspath())
 
 		# the task objects have changed: clear the signature cache
 		for tsk in lst:

waflib/Tools/fc_config.py

 		p = Utils.subprocess.Popen(cmd, stdin=stdin, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=env)
 		if stdin:
 			p.stdin.write('\n'.encode())
-		stdout, stderr = p.communicate()
-	except:
+		out, err = p.communicate()
+	except Exception:
 		conf.fatal('could not determine the compiler version %r' % cmd)
-	else:
-		if not isinstance(stdout, str):
-			stdout = stdout.decode(sys.stdout.encoding)
-		if not isinstance(stderr, str):
-			stderr = stderr.decode(sys.stdout.encoding)
-		return stdout, stderr
+	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)
 
 # ------------------------------------------------------------------------
 

waflib/Tools/ifort.py

 
 def configure(conf):
 	conf.find_ifort()
-	conf.find_ar()
+	conf.find_program('xiar', var='AR')
+	conf.env.ARFLAGS = 'rcs'
 	conf.fc_flags()
 	conf.ifort_modifier_platform()
 

waflib/Tools/msvc.py

 	def fun(tup):
 		return tup[0]
 
-	try:
-		detected_versions.sort(key = fun)
-	except:
-		# old python sort
-		detected_versions.sort(lambda x,y: cmp(x[0], y[0]))
+	detected_versions.sort(key = fun)
 	return detected_versions
 
 @conf

waflib/Tools/python.py

 		conf.fatal('The python version is too old, expecting %r' % (minver,))
 
 PYTHON_MODULE_TEMPLATE = '''
-import %s
-print(1)
+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):
+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
 	"""
-	conf.start_msg('Python module %s' % module_name)
+	msg = 'Python module %s' % module_name
+	if condition:
+		msg = '%s (%s)' % (msg, condition)
+	conf.start_msg(msg)
 	try:
-		conf.cmd_and_log(conf.env['PYTHON'] + ['-c', PYTHON_MODULE_TEMPLATE % module_name])
-	except:
+		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)
-	conf.end_msg(True)
+
+	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):
 	"""

waflib/Tools/tex.py

 		texinputs = self.env.TEXINPUTS or ''
 		self.TEXINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep + texinputs + os.pathsep
 
-		self.aux_node = node.change_ext('.aux') # TODO waf 1.7 remove (left for compatibility)
-
 		# important, set the cwd for everybody
 		self.cwd = self.inputs[0].parent.get_bld().abspath()
 

File contents unchanged.

waflib/extras/sync_exec.py

 # encoding: utf-8
 
 """
-Force the execution output to be synchronized
-May deadlock with a lot of output (subprocess limitation)
+This tool is obsolete, the sync_exec feature is now the default
 """
 
-import sys
-from waflib.Build import BuildContext
-from waflib import Utils, Logs
+pass
 
-def exec_command(self, cmd, **kw):
-	subprocess = Utils.subprocess
-	kw['shell'] = isinstance(cmd, str)
-	Logs.debug('runner: %r' % cmd)
-	Logs.debug('runner_env: kw=%s' % kw)
-	try:
-		kw['stdout'] = kw['stderr'] = subprocess.PIPE
-		p = subprocess.Popen(cmd, **kw)
-		(out, err) = p.communicate()
-		if out:
-			sys.stdout.write(out.decode(sys.stdout.encoding or 'iso8859-1'))
-		if err:
-			sys.stdout.write(err.decode(sys.stdout.encoding or 'iso8859-1'))
-		return p.returncode
-	except OSError:
-		return -1
-
-BuildContext.exec_command = exec_command
-
 """
 
 
-VERSION="1.6.10"
+VERSION="1.7.0"
 APPNAME='waf'
 REVISION=''
 
 demos = ['cpp', 'qt4', 'tex', 'ocaml', 'kde3', 'adv', 'cc', 'idl', 'docbook', 'xmlwaf', 'gnome']
 zip_types = ['bz2', 'gz']
 
-PRELUDE = '\timport waflib.extras.compat15'
+PRELUDE = ''
 
 #from tokenize import *
 import tokenize
 
 	f.close()
 	if path.endswith('.py') :
-		cnt = process_decorators(cnt)
-
-		if cnt.find('set(') > -1:
-			cnt = 'import sys\nif sys.hexversion < 0x020400f0: from sets import Set as set\n' + cnt
+		# 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
 
 	return (io.BytesIO(cnt.encode('utf-8')), len(cnt), cnt)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.