Fix environment

Change-Id: Ic053e2717a222f4db36e03ef1bba8a72c6bcaafa
diff --git a/.waf-tools/msvs.py b/.waf-tools/msvs.py
new file mode 100644
index 0000000..ef36e52
--- /dev/null
+++ b/.waf-tools/msvs.py
@@ -0,0 +1,1034 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Avalanche Studios 2009-2011
+# Thomas Nagy 2011
+
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+"""
+To add this tool to your project:
+def options(conf):
+	opt.load('msvs')
+
+It can be a good idea to add the sync_exec tool too.
+
+To generate solution files:
+$ waf configure msvs
+
+To customize the outputs, provide subclasses in your wscript files:
+
+from waflib.extras import msvs
+class vsnode_target(msvs.vsnode_target):
+	def get_build_command(self, props):
+		# likely to be required
+		return "waf.bat build"
+	def collect_source(self):
+		# likely to be required
+		...
+class msvs_bar(msvs.msvs_generator):
+	def init(self):
+		msvs.msvs_generator.init(self)
+		self.vsnode_target = vsnode_target
+
+The msvs class re-uses the same build() function for reading the targets (task generators),
+you may therefore specify msvs settings on the context object:
+
+def build(bld):
+	bld.solution_name = 'foo.sln'
+	bld.waf_command = 'waf.bat'
+	bld.projects_dir = bld.srcnode.make_node('.depproj')
+	bld.projects_dir.mkdir()
+
+For visual studio 2008, the command is called 'msvs2008', and the classes
+such as vsnode_target are wrapped by a decorator class 'wrap_2008' to
+provide special functionality.
+
+ASSUMPTIONS:
+* a project can be either a directory or a target, vcxproj files are written only for targets that have source files
+* each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path
+"""
+
+import os, re, sys
+import uuid # requires python 2.5
+from waflib.Build import BuildContext
+from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options
+
+HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
+
+PROJECT_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0"
+	xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+	<ItemGroup Label="ProjectConfigurations">
+		${for b in project.build_properties}
+		<ProjectConfiguration Include="${b.configuration}|${b.platform}">
+			<Configuration>${b.configuration}</Configuration>
+			<Platform>${b.platform}</Platform>
+		</ProjectConfiguration>
+		${endfor}
+	</ItemGroup>
+
+	<PropertyGroup Label="Globals">
+		<ProjectGuid>{${project.uuid}}</ProjectGuid>
+		<Keyword>MakeFileProj</Keyword>
+		<ProjectName>${project.name}</ProjectName>
+	</PropertyGroup>
+	<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+
+	${for b in project.build_properties}
+	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'" Label="Configuration">
+		<ConfigurationType>Makefile</ConfigurationType>
+		<OutDir>${b.outdir}</OutDir>
+		<PlatformToolset>v110</PlatformToolset>
+	</PropertyGroup>
+	${endfor}
+
+	<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+	<ImportGroup Label="ExtensionSettings">
+	</ImportGroup>
+
+	${for b in project.build_properties}
+	<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
+		<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+	</ImportGroup>
+	${endfor}
+
+	${for b in project.build_properties}
+	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
+		<NMakeBuildCommandLine>${xml:project.get_build_command(b)}</NMakeBuildCommandLine>
+		<NMakeReBuildCommandLine>${xml:project.get_rebuild_command(b)}</NMakeReBuildCommandLine>
+		<NMakeCleanCommandLine>${xml:project.get_clean_command(b)}</NMakeCleanCommandLine>
+		<NMakeIncludeSearchPath>${xml:b.includes_search_path}</NMakeIncludeSearchPath>
+		<NMakePreprocessorDefinitions>${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
+		<IncludePath>${xml:b.includes_search_path}</IncludePath>
+		<ExecutablePath>$(ExecutablePath)</ExecutablePath>
+
+		${if getattr(b, 'output_file', None)}
+		<NMakeOutput>${xml:b.output_file}</NMakeOutput>
+		${endif}
+		${if getattr(b, 'deploy_dir', None)}
+		<RemoteRoot>${xml:b.deploy_dir}</RemoteRoot>
+		${endif}
+	</PropertyGroup>
+	${endfor}
+
+	${for b in project.build_properties}
+		${if getattr(b, 'deploy_dir', None)}
+	<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
+		<Deploy>
+			<DeploymentType>CopyToHardDrive</DeploymentType>
+		</Deploy>
+	</ItemDefinitionGroup>
+		${endif}
+	${endfor}
+
+	<ItemGroup>
+		${for x in project.source}
+		<${project.get_key(x)} Include='${x.win32path()}' />
+		${endfor}
+	</ItemGroup>
+	<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+	<ImportGroup Label="ExtensionTargets">
+	</ImportGroup>
+</Project>
+'''
+
+FILTER_TEMPLATE = '''<?xml version="1.0" encoding="UTF-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+	<ItemGroup>
+		${for x in project.source}
+			<${project.get_key(x)} Include="${x.win32path()}">
+				<Filter>${project.get_filter_name(x.parent)}</Filter>
+			</${project.get_key(x)}>
+		${endfor}
+	</ItemGroup>
+	<ItemGroup>
+		${for x in project.dirs()}
+			<Filter Include="${project.get_filter_name(x)}">
+				<UniqueIdentifier>{${project.make_uuid(x.win32path())}}</UniqueIdentifier>
+			</Filter>
+		${endfor}
+	</ItemGroup>
+</Project>
+'''
+
+PROJECT_2008_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject ProjectType="Visual C++" Version="9,00"
+	Name="${xml: project.name}" ProjectGUID="{${project.uuid}}"
+	Keyword="MakeFileProj"
+	TargetFrameworkVersion="196613">
+	<Platforms>
+		${if project.build_properties}
+		${for b in project.build_properties}
+		   <Platform Name="${xml: b.platform}" />
+		${endfor}
+		${else}
+		   <Platform Name="Win32" />
+		${endif}
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		${if project.build_properties}
+		${for b in project.build_properties}
+		<Configuration
+			Name="${xml: b.configuration}|${xml: b.platform}"
+			IntermediateDirectory="$ConfigurationName"
+			OutputDirectory="${xml: b.outdir}"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="${xml: project.get_build_command(b)}"
+				ReBuildCommandLine="${xml: project.get_rebuild_command(b)}"
+				CleanCommandLine="${xml: project.get_clean_command(b)}"
+				${if getattr(b, 'output_file', None)}
+				Output="${xml: b.output_file}"
+				${endif}
+				PreprocessorDefinitions="${xml: b.preprocessor_definitions}"
+				IncludeSearchPath="${xml: b.includes_search_path}"
+				ForcedIncludes=""
+				ForcedUsingAssemblies=""
+				AssemblySearchPath=""
+				CompileAsManaged=""
+			/>
+		</Configuration>
+		${endfor}
+		${else}
+			<Configuration Name="Release|Win32" >
+		</Configuration>
+		${endif}
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+${project.display_filter()}
+	</Files>
+</VisualStudioProject>
+'''
+
+SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver}
+# Visual Studio ${project.vsver}
+${for p in project.all_projects}
+Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}"
+EndProject${endfor}
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		${if project.all_projects}
+		${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()}
+		${configuration}|${platform} = ${configuration}|${platform}
+		${endfor}
+		${endif}
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		${for p in project.all_projects}
+			${if hasattr(p, 'source')}
+			${for b in p.build_properties}
+		{${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform}
+			${if getattr(p, 'is_active', None)}
+		{${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform}
+			${endif}
+			${if getattr(p, 'is_deploy', None)}
+		{${p.uuid}}.${b.configuration}|${b.platform}.Deploy.0 = ${b.configuration}|${b.platform}
+			${endif}
+			${endfor}
+			${endif}
+		${endfor}
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+	${for p in project.all_projects}
+		${if p.parent}
+		{${p.uuid}} = {${p.parent.uuid}}
+		${endif}
+	${endfor}
+	EndGlobalSection
+EndGlobal
+'''
+
+COMPILE_TEMPLATE = '''def f(project):
+	lst = []
+	def xml_escape(value):
+		return value.replace("&", "&amp;").replace('"', "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;")
+
+	%s
+
+	#f = open('cmd.txt', 'w')
+	#f.write(str(lst))
+	#f.close()
+	return ''.join(lst)
+'''
+reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M)
+def compile_template(line):
+	"""
+	Compile a template expression into a python function (like jsps, but way shorter)
+	"""
+	extr = []
+	def repl(match):
+		g = match.group
+		if g('dollar'): return "$"
+		elif g('backslash'):
+			return "\\"
+		elif g('subst'):
+			extr.append(g('code'))
+			return "<<|@|>>"
+		return None
+
+	line2 = reg_act.sub(repl, line)
+	params = line2.split('<<|@|>>')
+	assert(extr)
+
+
+	indent = 0
+	buf = []
+	app = buf.append
+
+	def app(txt):
+		buf.append(indent * '\t' + txt)
+
+	for x in range(len(extr)):
+		if params[x]:
+			app("lst.append(%r)" % params[x])
+
+		f = extr[x]
+		if f.startswith('if') or f.startswith('for'):
+			app(f + ':')
+			indent += 1
+		elif f.startswith('py:'):
+			app(f[3:])
+		elif f.startswith('endif') or f.startswith('endfor'):
+			indent -= 1
+		elif f.startswith('else') or f.startswith('elif'):
+			indent -= 1
+			app(f + ':')
+			indent += 1
+		elif f.startswith('xml:'):
+			app('lst.append(xml_escape(%s))' % f[4:])
+		else:
+			#app('lst.append((%s) or "cannot find %s")' % (f, f))
+			app('lst.append(%s)' % f)
+
+	if extr:
+		if params[-1]:
+			app("lst.append(%r)" % params[-1])
+
+	fun = COMPILE_TEMPLATE % "\n\t".join(buf)
+	#print(fun)
+	return Task.funex(fun)
+
+
+re_blank = re.compile('(\n|\r|\\s)*\n', re.M)
+def rm_blank_lines(txt):
+	txt = re_blank.sub('\r\n', txt)
+	return txt
+
+BOM = '\xef\xbb\xbf'
+try:
+	BOM = bytes(BOM, 'iso8859-1') # python 3
+except TypeError:
+	pass
+
+def stealth_write(self, data, flags='wb'):
+	try:
+		unicode
+	except NameError:
+		data = data.encode('utf-8') # python 3
+	else:
+		data = data.decode(sys.getfilesystemencoding(), 'replace')
+		data = data.encode('utf-8')
+
+	if self.name.endswith('.vcproj') or self.name.endswith('.vcxproj'):
+		data = BOM + data
+
+	try:
+		txt = self.read(flags='rb')
+		if txt != data:
+			raise ValueError('must write')
+	except (IOError, ValueError):
+		self.write(data, flags=flags)
+	else:
+		Logs.debug('msvs: skipping %s' % self.win32path())
+Node.Node.stealth_write = stealth_write
+
+re_win32 = re.compile(r'^([/\\]cygdrive)?[/\\]([a-z])([^a-z0-9_-].*)', re.I)
+def win32path(self):
+	p = self.abspath()
+	m = re_win32.match(p)
+	if m:
+		return "%s:%s" % (m.group(2).upper(), m.group(3))
+	return p
+Node.Node.win32path = win32path
+
+re_quote = re.compile("[^a-zA-Z0-9-]")
+def quote(s):
+	return re_quote.sub("_", s)
+
+def xml_escape(value):
+	return value.replace("&", "&amp;").replace('"', "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;")
+
+def make_uuid(v, prefix = None):
+	"""
+	simple utility function
+	"""
+	if isinstance(v, dict):
+		keys = list(v.keys())
+		keys.sort()
+		tmp = str([(k, v[k]) for k in keys])
+	else:
+		tmp = str(v)
+	d = Utils.md5(tmp.encode()).hexdigest().upper()
+	if prefix:
+		d = '%s%s' % (prefix, d[8:])
+	gid = uuid.UUID(d, version = 4)
+	return str(gid).upper()
+
+def diff(node, fromnode):
+	# difference between two nodes, but with "(..)" instead of ".."
+	c1 = node
+	c2 = fromnode
+
+	c1h = c1.height()
+	c2h = c2.height()
+
+	lst = []
+	up = 0
+
+	while c1h > c2h:
+		lst.append(c1.name)
+		c1 = c1.parent
+		c1h -= 1
+
+	while c2h > c1h:
+		up += 1
+		c2 = c2.parent
+		c2h -= 1
+
+	while id(c1) != id(c2):
+		lst.append(c1.name)
+		up += 1
+
+		c1 = c1.parent
+		c2 = c2.parent
+
+	for i in range(up):
+		lst.append('(..)')
+	lst.reverse()
+	return tuple(lst)
+
+class build_property(object):
+	pass
+
+class vsnode(object):
+	"""
+	Abstract class representing visual studio elements
+	We assume that all visual studio nodes have a uuid and a parent
+	"""
+	def __init__(self, ctx):
+		self.ctx = ctx # msvs context
+		self.name = '' # string, mandatory
+		self.vspath = '' # path in visual studio (name for dirs, absolute path for projects)
+		self.uuid = '' # string, mandatory
+		self.parent = None # parent node for visual studio nesting
+
+	def get_waf(self):
+		"""
+		Override in subclasses...
+		"""
+		return 'cd /d "%s" & %s' % (self.ctx.srcnode.win32path(), getattr(self.ctx, 'waf_command', 'waf.bat'))
+
+	def ptype(self):
+		"""
+		Return a special uuid for projects written in the solution file
+		"""
+		pass
+
+	def write(self):
+		"""
+		Write the project file, by default, do nothing
+		"""
+		pass
+
+	def make_uuid(self, val):
+		"""
+		Alias for creating uuid values easily (the templates cannot access global variables)
+		"""
+		return make_uuid(val)
+
+class vsnode_vsdir(vsnode):
+	"""
+	Nodes representing visual studio folders (which do not match the filesystem tree!)
+	"""
+	VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
+	def __init__(self, ctx, uuid, name, vspath=''):
+		vsnode.__init__(self, ctx)
+		self.title = self.name = name
+		self.uuid = uuid
+		self.vspath = vspath or name
+
+	def ptype(self):
+		return self.VS_GUID_SOLUTIONFOLDER
+
+class vsnode_project(vsnode):
+	"""
+	Abstract class representing visual studio project elements
+	A project is assumed to be writable, and has a node representing the file to write to
+	"""
+	VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
+	def ptype(self):
+		return self.VS_GUID_VCPROJ
+
+	def __init__(self, ctx, node):
+		vsnode.__init__(self, ctx)
+		self.path = node
+		self.uuid = make_uuid(node.win32path())
+		self.name = node.name
+		self.title = self.path.win32path()
+		self.source = [] # list of node objects
+		self.build_properties = [] # list of properties (nmake commands, output dir, etc)
+
+	def dirs(self):
+		"""
+		Get the list of parent folders of the source files (header files included)
+		for writing the filters
+		"""
+		lst = []
+		def add(x):
+			if x.height() > self.tg.path.height() and x not in lst:
+				lst.append(x)
+				add(x.parent)
+		for x in self.source:
+			add(x.parent)
+		return lst
+
+	def write(self):
+		Logs.debug('msvs: creating %r' % self.path)
+
+		# first write the project file
+		template1 = compile_template(PROJECT_TEMPLATE)
+		proj_str = template1(self)
+		proj_str = rm_blank_lines(proj_str)
+		self.path.stealth_write(proj_str)
+
+		# then write the filter
+		template2 = compile_template(FILTER_TEMPLATE)
+		filter_str = template2(self)
+		filter_str = rm_blank_lines(filter_str)
+		tmp = self.path.parent.make_node(self.path.name + '.filters')
+		tmp.stealth_write(filter_str)
+
+	def get_key(self, node):
+		"""
+		required for writing the source files
+		"""
+		name = node.name
+		if name.endswith('.cpp') or name.endswith('.c'):
+			return 'ClCompile'
+		return 'ClInclude'
+
+	def collect_properties(self):
+		"""
+		Returns a list of triplet (configuration, platform, output_directory)
+		"""
+		ret = []
+		for c in self.ctx.configurations:
+			for p in self.ctx.platforms:
+				x = build_property()
+				x.outdir = ''
+
+				x.configuration = c
+				x.platform = p
+
+				x.preprocessor_definitions = ''
+				x.includes_search_path = ''
+
+				# can specify "deploy_dir" too
+				ret.append(x)
+		self.build_properties = ret
+
+	def get_build_params(self, props):
+		opt = '--execsolution=%s' % self.ctx.get_solution_node().win32path()
+		return (self.get_waf(), opt)
+
+	def get_build_command(self, props):
+		return "%s build %s" % self.get_build_params(props)
+
+	def get_clean_command(self, props):
+		return "%s clean %s" % self.get_build_params(props)
+
+	def get_rebuild_command(self, props):
+		return "%s clean build %s" % self.get_build_params(props)
+
+	def get_filter_name(self, node):
+		lst = diff(node, self.tg.path)
+		return '\\'.join(lst) or '.'
+
+class vsnode_alias(vsnode_project):
+	def __init__(self, ctx, node, name):
+		vsnode_project.__init__(self, ctx, node)
+		self.name = name
+		self.output_file = ''
+
+class vsnode_build_all(vsnode_alias):
+	"""
+	Fake target used to emulate the behaviour of "make all" (starting one process by target is slow)
+	This is the only alias enabled by default
+	"""
+	def __init__(self, ctx, node, name='build_all_projects'):
+		vsnode_alias.__init__(self, ctx, node, name)
+		self.is_active = True
+
+class vsnode_install_all(vsnode_alias):
+	"""
+	Fake target used to emulate the behaviour of "make install"
+	"""
+	def __init__(self, ctx, node, name='install_all_projects'):
+		vsnode_alias.__init__(self, ctx, node, name)
+
+	def get_build_command(self, props):
+		return "%s build install %s" % self.get_build_params(props)
+
+	def get_clean_command(self, props):
+		return "%s clean %s" % self.get_build_params(props)
+
+	def get_rebuild_command(self, props):
+		return "%s clean build install %s" % self.get_build_params(props)
+
+class vsnode_project_view(vsnode_alias):
+	"""
+	Fake target used to emulate a file system view
+	"""
+	def __init__(self, ctx, node, name='project_view'):
+		vsnode_alias.__init__(self, ctx, node, name)
+		self.tg = self.ctx() # fake one, cannot remove
+		self.exclude_files = Node.exclude_regs + '''
+waf-1.8.*
+waf3-1.8.*/**
+.waf-1.8.*
+.waf3-1.8.*/**
+**/*.sdf
+**/*.suo
+**/*.ncb
+**/%s
+		''' % Options.lockfile
+
+	def collect_source(self):
+		# this is likely to be slow
+		self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files)
+
+	def get_build_command(self, props):
+		params = self.get_build_params(props) + (self.ctx.cmd,)
+		return "%s %s %s" % params
+
+	def get_clean_command(self, props):
+		return ""
+
+	def get_rebuild_command(self, props):
+		return self.get_build_command(props)
+
+class vsnode_target(vsnode_project):
+	"""
+	Visual studio project representing a targets (programs, libraries, etc) and bound
+	to a task generator
+	"""
+	def __init__(self, ctx, tg):
+		"""
+		A project is more or less equivalent to a file/folder
+		"""
+		base = getattr(ctx, 'projects_dir', None) or tg.path
+		node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node
+		vsnode_project.__init__(self, ctx, node)
+		self.name = quote(tg.name)
+		self.tg     = tg  # task generator
+
+	def get_build_params(self, props):
+		"""
+		Override the default to add the target name
+		"""
+		opt = '--execsolution=%s' % self.ctx.get_solution_node().win32path()
+		if getattr(self, 'tg', None):
+			opt += " --targets=%s" % self.tg.name
+		return (self.get_waf(), opt)
+
+	def collect_source(self):
+		tg = self.tg
+		source_files = tg.to_nodes(getattr(tg, 'source', []))
+		include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', []))
+		include_files = []
+		for x in include_dirs:
+			if isinstance(x, str):
+				x = tg.path.find_node(x)
+			if x:
+				lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)]
+				include_files.extend(lst)
+
+		# remove duplicates
+		self.source.extend(list(set(source_files + include_files)))
+		self.source.sort(key=lambda x: x.win32path())
+
+	def collect_properties(self):
+		"""
+		Visual studio projects are associated with platforms and configurations (for building especially)
+		"""
+		super(vsnode_target, self).collect_properties()
+		for x in self.build_properties:
+			x.outdir = self.path.parent.win32path()
+			x.preprocessor_definitions = ''
+			x.includes_search_path = ''
+
+			try:
+				tsk = self.tg.link_task
+			except AttributeError:
+				pass
+			else:
+				x.output_file = tsk.outputs[0].win32path()
+				x.preprocessor_definitions = ';'.join(tsk.env.DEFINES)
+				x.includes_search_path = ';'.join(self.tg.env.INCPATHS)
+
+class msvs_generator(BuildContext):
+	'''generates a visual studio 2010 solution'''
+	cmd = 'msvs'
+	fun = 'build'
+
+	def init(self):
+		"""
+		Some data that needs to be present
+		"""
+		if not getattr(self, 'configurations', None):
+			self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc
+		if not getattr(self, 'platforms', None):
+			self.platforms = ['Win32']
+		if not getattr(self, 'all_projects', None):
+			self.all_projects = []
+		if not getattr(self, 'project_extension', None):
+			self.project_extension = '.vcxproj'
+		if not getattr(self, 'projects_dir', None):
+			self.projects_dir = self.srcnode.make_node('.depproj')
+			self.projects_dir.mkdir()
+
+		# bind the classes to the object, so that subclass can provide custom generators
+		if not getattr(self, 'vsnode_vsdir', None):
+			self.vsnode_vsdir = vsnode_vsdir
+		if not getattr(self, 'vsnode_target', None):
+			self.vsnode_target = vsnode_target
+		if not getattr(self, 'vsnode_build_all', None):
+			self.vsnode_build_all = vsnode_build_all
+		if not getattr(self, 'vsnode_install_all', None):
+			self.vsnode_install_all = vsnode_install_all
+		if not getattr(self, 'vsnode_project_view', None):
+			self.vsnode_project_view = vsnode_project_view
+
+		self.numver = '11.00'
+		self.vsver  = '2010'
+
+	def execute(self):
+		"""
+		Entry point
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+		self.recurse([self.run_dir])
+
+		# user initialization
+		self.init()
+
+		# two phases for creating the solution
+		self.collect_projects() # add project objects into "self.all_projects"
+		self.write_files() # write the corresponding project and solution files
+
+	def collect_projects(self):
+		"""
+		Fill the list self.all_projects with project objects
+		Fill the list of build targets
+		"""
+		self.collect_targets()
+		self.add_aliases()
+		self.collect_dirs()
+		default_project = getattr(self, 'default_project', None)
+		def sortfun(x):
+			if x.name == default_project:
+				return ''
+			return getattr(x, 'path', None) and x.path.win32path() or x.name
+		self.all_projects.sort(key=sortfun)
+
+	def write_files(self):
+		"""
+		Write the project and solution files from the data collected
+		so far. It is unlikely that you will want to change this
+		"""
+		for p in self.all_projects:
+			p.write()
+
+		# and finally write the solution file
+		node = self.get_solution_node()
+		node.parent.mkdir()
+		Logs.warn('Creating %r' % node)
+		template1 = compile_template(SOLUTION_TEMPLATE)
+		sln_str = template1(self)
+		sln_str = rm_blank_lines(sln_str)
+		node.stealth_write(sln_str)
+
+	def get_solution_node(self):
+		"""
+		The solution filename is required when writing the .vcproj files
+		return self.solution_node and if it does not exist, make one
+		"""
+		try:
+			return self.solution_node
+		except AttributeError:
+			pass
+
+		solution_name = getattr(self, 'solution_name', None)
+		if not solution_name:
+			solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln'
+		if os.path.isabs(solution_name):
+			self.solution_node = self.root.make_node(solution_name)
+		else:
+			self.solution_node = self.srcnode.make_node(solution_name)
+		return self.solution_node
+
+	def project_configurations(self):
+		"""
+		Helper that returns all the pairs (config,platform)
+		"""
+		ret = []
+		for c in self.configurations:
+			for p in self.platforms:
+				ret.append((c, p))
+		return ret
+
+	def collect_targets(self):
+		"""
+		Process the list of task generators
+		"""
+		for g in self.groups:
+			for tg in g:
+				if not isinstance(tg, TaskGen.task_gen):
+					continue
+
+				if not hasattr(tg, 'msvs_includes'):
+					tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', []))
+				tg.post()
+				if not getattr(tg, 'link_task', None):
+					continue
+
+				p = self.vsnode_target(self, tg)
+				p.collect_source() # delegate this processing
+				p.collect_properties()
+				self.all_projects.append(p)
+
+	def add_aliases(self):
+		"""
+		Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7
+		We also add an alias for "make install" (disabled by default)
+		"""
+		base = getattr(self, 'projects_dir', None) or self.tg.path
+
+		node_project = base.make_node('build_all_projects' + self.project_extension) # Node
+		p_build = self.vsnode_build_all(self, node_project)
+		p_build.collect_properties()
+		self.all_projects.append(p_build)
+
+		node_project = base.make_node('install_all_projects' + self.project_extension) # Node
+		p_install = self.vsnode_install_all(self, node_project)
+		p_install.collect_properties()
+		self.all_projects.append(p_install)
+
+		node_project = base.make_node('project_view' + self.project_extension) # Node
+		p_view = self.vsnode_project_view(self, node_project)
+		p_view.collect_source()
+		p_view.collect_properties()
+		self.all_projects.append(p_view)
+
+		n = self.vsnode_vsdir(self, make_uuid(self.srcnode.win32path() + 'build_aliases'), "build_aliases")
+		p_build.parent = p_install.parent = p_view.parent = n
+		self.all_projects.append(n)
+
+	def collect_dirs(self):
+		"""
+		Create the folder structure in the Visual studio project view
+		"""
+		seen = {}
+		def make_parents(proj):
+			# look at a project, try to make a parent
+			if getattr(proj, 'parent', None):
+				# aliases already have parents
+				return
+			x = proj.iter_path
+			if x in seen:
+				proj.parent = seen[x]
+				return
+
+			# There is not vsnode_vsdir for x.
+			# So create a project representing the folder "x"
+			n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.win32path()), x.name)
+			n.iter_path = x.parent
+			self.all_projects.append(n)
+
+			# recurse up to the project directory
+			if x.height() > self.srcnode.height() + 1:
+				make_parents(n)
+
+		for p in self.all_projects[:]: # iterate over a copy of all projects
+			if not getattr(p, 'tg', None):
+				# but only projects that have a task generator
+				continue
+
+			# make a folder for each task generator
+			p.iter_path = p.tg.path
+			make_parents(p)
+
+def wrap_2008(cls):
+	class dec(cls):
+		def __init__(self, *k, **kw):
+			cls.__init__(self, *k, **kw)
+			self.project_template = PROJECT_2008_TEMPLATE
+
+		def display_filter(self):
+
+			root = build_property()
+			root.subfilters = []
+			root.sourcefiles = []
+			root.source = []
+			root.name = ''
+
+			@Utils.run_once
+			def add_path(lst):
+				if not lst:
+					return root
+				child = build_property()
+				child.subfilters = []
+				child.sourcefiles = []
+				child.source = []
+				child.name = lst[-1]
+
+				par = add_path(lst[:-1])
+				par.subfilters.append(child)
+				return child
+
+			for x in self.source:
+				# this crap is for enabling subclasses to override get_filter_name
+				tmp = self.get_filter_name(x.parent)
+				tmp = tmp != '.' and tuple(tmp.split('\\')) or ()
+				par = add_path(tmp)
+				par.source.append(x)
+
+			def display(n):
+				buf = []
+				for x in n.source:
+					buf.append('<File RelativePath="%s" FileType="%s"/>\n' % (xml_escape(x.win32path()), self.get_key(x)))
+				for x in n.subfilters:
+					buf.append('<Filter Name="%s">' % xml_escape(x.name))
+					buf.append(display(x))
+					buf.append('</Filter>')
+				return '\n'.join(buf)
+
+			return display(root)
+
+		def get_key(self, node):
+			"""
+			If you do not want to let visual studio use the default file extensions,
+			override this method to return a value:
+				0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form,
+				4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File,
+				8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File,
+				13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon,
+				18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service,
+				22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File,
+				26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document,
+				29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC
+			"""
+			return ''
+
+		def write(self):
+			Logs.debug('msvs: creating %r' % self.path)
+			template1 = compile_template(self.project_template)
+			proj_str = template1(self)
+			proj_str = rm_blank_lines(proj_str)
+			self.path.stealth_write(proj_str)
+
+	return dec
+
+class msvs_2008_generator(msvs_generator):
+	'''generates a visual studio 2008 solution'''
+	cmd = 'msvs2008'
+	fun = msvs_generator.fun
+
+	def init(self):
+		if not getattr(self, 'project_extension', None):
+			self.project_extension = '_2008.vcproj'
+		if not getattr(self, 'solution_name', None):
+			self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln'
+
+		if not getattr(self, 'vsnode_target', None):
+			self.vsnode_target = wrap_2008(vsnode_target)
+		if not getattr(self, 'vsnode_build_all', None):
+			self.vsnode_build_all = wrap_2008(vsnode_build_all)
+		if not getattr(self, 'vsnode_install_all', None):
+			self.vsnode_install_all = wrap_2008(vsnode_install_all)
+		if not getattr(self, 'vsnode_project_view', None):
+			self.vsnode_project_view = wrap_2008(vsnode_project_view)
+
+		msvs_generator.init(self)
+		self.numver = '10.00'
+		self.vsver  = '2008'
+
+def options(ctx):
+	"""
+	If the msvs option is used, try to detect if the build is made from visual studio
+	"""
+	ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file')
+
+	old = BuildContext.execute
+	def override_build_state(ctx):
+		def lock(rm, add):
+			uns = ctx.options.execsolution.replace('.sln', rm)
+			uns = ctx.root.make_node(uns)
+			try:
+				uns.delete()
+			except OSError:
+				pass
+
+			uns = ctx.options.execsolution.replace('.sln', add)
+			uns = ctx.root.make_node(uns)
+			try:
+				uns.write('')
+			except EnvironmentError:
+				pass
+
+		if ctx.options.execsolution:
+			ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio)
+			lock('.lastbuildstate', '.unsuccessfulbuild')
+			old(ctx)
+			lock('.unsuccessfulbuild', '.lastbuildstate')
+		else:
+			old(ctx)
+	BuildContext.execute = override_build_state
+