#! /usr/bin/env python
# encoding: utf-8
# WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file

import os,sys,re,tempfile
from waflib import Utils,Task,Logs,Options,Errors
from waflib.Logs import debug,warn
from waflib.TaskGen import after_method,feature
from waflib.Configure import conf
from waflib.Tools import ccroot,c,cxx,ar,winres
g_msvc_systemlibs='''
aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs
credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d
ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp
faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid
gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop
kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi
mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree
msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm
netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp
odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32
osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu
ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm
rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32
shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32
traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg
version vfw32 wbemuuid  webpost wiaguid wininet winmm winscard winspool winstrm
wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp
'''.split()
all_msvc_platforms=[('x64','amd64'),('x86','x86'),('ia64','ia64'),('x86_amd64','amd64'),('x86_ia64','ia64'),('x86_arm','arm')]
all_wince_platforms=[('armv4','arm'),('armv4i','arm'),('mipsii','mips'),('mipsii_fp','mips'),('mipsiv','mips'),('mipsiv_fp','mips'),('sh4','sh'),('x86','cex86')]
all_icl_platforms=[('intel64','amd64'),('em64t','amd64'),('ia32','x86'),('Itanium','ia64')]
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='')
def setup_msvc(conf,versions,arch=False):
	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]
	desired_versions=getattr(Options.options,'msvc_version','').split(',')
	if desired_versions==['']:
		desired_versions=conf.env['MSVC_VERSIONS']or[v for v,_ in versions][::-1]
	versiondict=dict(versions)
	for version in desired_versions:
		try:
			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
					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)')
@conf
def get_msvc_version(conf,compiler,version,target,vcvars):
	debug('msvc: get_msvc_version: %r %r %r',compiler,version,target)
	batfile=conf.bldnode.make_node('waf-print-msvc.bat')
	batfile.write("""@echo off
set INCLUDE=
set LIB=
call "%s" %s
echo PATH=%%PATH%%
echo INCLUDE=%%INCLUDE%%
echo LIB=%%LIB%%;%%LIBPATH%%
"""%(vcvars,target))
	sout=conf.cmd_and_log(['cmd','/E:on','/V:on','/C',batfile.abspath()])
	lines=sout.splitlines()
	if not lines[0]:
		lines.pop(0)
	MSVC_PATH=MSVC_INCDIR=MSVC_LIBDIR=None
	for line in lines:
		if line.startswith('PATH='):
			path=line[5:]
			MSVC_PATH=path.split(';')
		elif line.startswith('INCLUDE='):
			MSVC_INCDIR=[i for i in line[8:].split(';')if i]
		elif line.startswith('LIB='):
			MSVC_LIBDIR=[i for i in line[4:].split(';')if i]
	if None in(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR):
		conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_3)')
	env=dict(os.environ)
	env.update(PATH=path)
	compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler)
	cxx=conf.find_program(compiler_name,path_list=MSVC_PATH)
	cxx=conf.cmd_to_list(cxx)
	if'CL'in env:
		del(env['CL'])
	try:
		try:
			conf.cmd_and_log(cxx+['/help'],env=env)
		except Exception ,e:
			debug('msvc: get_msvc_version: %r %r %r -> failure'%(compiler,version,target))
			debug(str(e))
			conf.fatal('msvc: cannot run the compiler (in get_msvc_version)')
		else:
			debug('msvc: get_msvc_version: %r %r %r -> OK',compiler,version,target)
	finally:
		conf.env[compiler_name]=''
	return(MSVC_PATH,MSVC_INCDIR,MSVC_LIBDIR)
@conf
def gather_wsdk_versions(conf,versions):
	version_pattern=re.compile('^v..?.?\...?.?')
	try:
		all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
	except WindowsError:
		try:
			all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
		except WindowsError:
			return
	index=0
	while 1:
		try:
			version=Utils.winreg.EnumKey(all_versions,index)
		except WindowsError:
			break
		index=index+1
		if not version_pattern.match(version):
			continue
		try:
			msvc_version=Utils.winreg.OpenKey(all_versions,version)
			path,type=Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder')
		except WindowsError:
			continue
		if os.path.isfile(os.path.join(path,'bin','SetEnv.cmd')):
			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')))))
				except conf.errors.ConfigurationError:
					pass
			versions.append(('wsdk '+version[1:],targets))
def gather_wince_supported_platforms():
	supported_wince_platforms=[]
	try:
		ce_sdk=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')
	except WindowsError:
		try:
			ce_sdk=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')
		except WindowsError:
			ce_sdk=''
	if not ce_sdk:
		return supported_wince_platforms
	ce_index=0
	while 1:
		try:
			sdk_device=Utils.winreg.EnumKey(ce_sdk,ce_index)
		except WindowsError:
			break
		ce_index=ce_index+1
		sdk=Utils.winreg.OpenKey(ce_sdk,sdk_device)
		try:
			path,type=Utils.winreg.QueryValueEx(sdk,'SDKRootDir')
		except WindowsError:
			try:
				path,type=Utils.winreg.QueryValueEx(sdk,'SDKInformation')
				path,xml=os.path.split(path)
			except WindowsError:
				continue
		path=str(path)
		path,device=os.path.split(path)
		if not device:
			path,device=os.path.split(path)
		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))
	return supported_wince_platforms
def gather_msvc_detected_versions():
	version_pattern=re.compile('^(\d\d?\.\d\d?)(Exp)?$')
	detected_versions=[]
	for vcver,vcvar in[('VCExpress','Exp'),('VisualStudio','')]:
		try:
			prefix='SOFTWARE\\Wow6432node\\Microsoft\\'+vcver
			all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,prefix)
		except WindowsError:
			try:
				prefix='SOFTWARE\\Microsoft\\'+vcver
				all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,prefix)
			except WindowsError:
				continue
		index=0
		while 1:
			try:
				version=Utils.winreg.EnumKey(all_versions,index)
			except WindowsError:
				break
			index=index+1
			match=version_pattern.match(version)
			if not match:
				continue
			else:
				versionnumber=float(match.group(1))
			detected_versions.append((versionnumber,version+vcvar,prefix+"\\"+version))
	def fun(tup):
		return tup[0]
	detected_versions.sort(key=fun)
	return detected_versions
@conf
def gather_msvc_targets(conf,versions,version,vc_path):
	targets=[]
	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')))))
			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')))))
		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')))))
		except conf.errors.ConfigurationError:
			pass
	if targets:
		versions.append(('msvc '+version,targets))
@conf
def gather_wince_targets(conf,versions,version,vc_path,vsvars,supported_platforms):
	for device,platforms in supported_platforms:
		cetargets=[]
		for platform,compiler,include,lib in platforms:
			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
				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))))
		if cetargets:
			versions.append((device+' '+version,cetargets))
@conf
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 ,e:
			pass
	if targets:
		versions.append(('winphone '+version,targets))
@conf
def gather_msvc_versions(conf,versions):
	vc_paths=[]
	for(v,version,reg)in gather_msvc_detected_versions():
		try:
			try:
				msvc_version=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,reg+"\\Setup\\VC")
			except WindowsError:
				msvc_version=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,reg+"\\Setup\\Microsoft Visual C++")
			path,type=Utils.winreg.QueryValueEx(msvc_version,'ProductDir')
			vc_paths.append((version,os.path.abspath(str(path))))
		except WindowsError:
			continue
	wince_supported_platforms=gather_wince_supported_platforms()
	for version,vc_path in vc_paths:
		vs_path=os.path.dirname(vc_path)
		vsvars=os.path.join(vs_path,'Common7','Tools','vsvars32.bat')
		if wince_supported_platforms and os.path.isfile(vsvars):
			conf.gather_wince_targets(versions,version,vc_path,vsvars,wince_supported_platforms)
		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)
	for version,vc_path in vc_paths:
		vs_path=os.path.dirname(vc_path)
		conf.gather_msvc_targets(versions,version,vc_path)
@conf
def gather_icl_versions(conf,versions):
	version_pattern=re.compile('^...?.?\....?.?')
	try:
		all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')
	except WindowsError:
		try:
			all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Intel\\Compilers\\C++')
		except WindowsError:
			return
	index=0
	while 1:
		try:
			version=Utils.winreg.EnumKey(all_versions,index)
		except WindowsError:
			break
		index=index+1
		if not version_pattern.match(version):
			continue
		targets=[]
		for target,arch in all_icl_platforms:
			try:
				if target=='intel64':targetDir='EM64T_NATIVE'
				else:targetDir=target
				Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir)
				icl_version=Utils.winreg.OpenKey(all_versions,version)
				path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
				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:
						pass
			except WindowsError:
				pass
		for target,arch in all_icl_platforms:
			try:
				icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+target)
				path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
				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:
						pass
			except WindowsError:
				continue
		major=version[0:2]
		versions.append(('intel '+major,targets))
@conf
def gather_intel_composer_versions(conf,versions):
	version_pattern=re.compile('^...?.?\...?.?.?')
	try:
		all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Wow6432node\\Intel\\Suites')
	except WindowsError:
		try:
			all_versions=Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Intel\\Suites')
		except WindowsError:
			return
	index=0
	while 1:
		try:
			version=Utils.winreg.EnumKey(all_versions,index)
		except WindowsError:
			break
		index=index+1
		if not version_pattern.match(version):
			continue
		targets=[]
		for target,arch in all_icl_platforms:
			try:
				if target=='intel64':targetDir='EM64T_NATIVE'
				else:targetDir=target
				try:
					defaults=Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir)
				except WindowsError:
					if targetDir=='EM64T_NATIVE':
						defaults=Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T')
					else:
						raise WindowsError
				uid,type=Utils.winreg.QueryValueEx(defaults,'SubKey')
				Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++\\'+targetDir)
				icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++')
				path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')
				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 ,e:
						pass
				compilervars_warning_attr='_compilervars_warning_key'
				if version[0:2]=='13'and getattr(conf,compilervars_warning_attr,True):
					setattr(conf,compilervars_warning_attr,False)
					patch_url='http://software.intel.com/en-us/forums/topic/328487'
					compilervars_arch=os.path.join(path,'bin','compilervars_arch.bat')
					for vscomntools in['VS110COMNTOOLS','VS100COMNTOOLS']:
						if os.environ.has_key(vscomntools):
							vs_express_path=os.environ[vscomntools]+r'..\IDE\VSWinExpress.exe'
							dev_env_path=os.environ[vscomntools]+r'..\IDE\devenv.exe'
							if(r'if exist "%VS110COMNTOOLS%..\IDE\VSWinExpress.exe"'in Utils.readf(compilervars_arch)and not os.path.exists(vs_express_path)and not os.path.exists(dev_env_path)):
								Logs.warn(('The Intel compilervar_arch.bat only checks for one Visual Studio SKU ''(VSWinExpress.exe) but it does not seem to be installed at %r. ''The intel command line set up will fail to configure unless the file %r''is patched. See: %s')%(vs_express_path,compilervars_arch,patch_url))
			except WindowsError:
				pass
		major=version[0:2]
		versions.append(('intel '+major,targets))
@conf
def get_msvc_versions(conf):
	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)
		conf.env['MSVC_INSTALLED_VERSIONS']=lst
	return conf.env['MSVC_INSTALLED_VERSIONS']
@conf
def print_all_msvc_detected(conf):
	for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']:
		Logs.info(version)
		for target,l in targets:
			Logs.info("\t"+target)
@conf
def detect_msvc(conf,arch=False):
	versions=get_msvc_versions(conf)
	return setup_msvc(conf,versions,arch)
@conf
def find_lt_names_msvc(self,libname,is_static=False):
	lt_names=['lib%s.la'%libname,'%s.la'%libname,]
	for path in self.env['LIBPATH']:
		for la in lt_names:
			laf=os.path.join(path,la)
			dll=None
			if os.path.exists(laf):
				ltdict=Utils.read_la_file(laf)
				lt_libdir=None
				if ltdict.get('libdir',''):
					lt_libdir=ltdict['libdir']
				if not is_static and ltdict.get('library_names',''):
					dllnames=ltdict['library_names'].split()
					dll=dllnames[0].lower()
					dll=re.sub('\.dll$','',dll)
					return(lt_libdir,dll,False)
				elif ltdict.get('old_library',''):
					olib=ltdict['old_library']
					if os.path.exists(os.path.join(path,olib)):
						return(path,olib,True)
					elif lt_libdir!=''and os.path.exists(os.path.join(lt_libdir,olib)):
						return(lt_libdir,olib,True)
					else:
						return(None,olib,True)
				else:
					raise self.errors.WafError('invalid libtool object file: %s'%laf)
	return(None,None,None)
@conf
def libname_msvc(self,libname,is_static=False):
	lib=libname.lower()
	lib=re.sub('\.lib$','',lib)
	if lib in g_msvc_systemlibs:
		return lib
	lib=re.sub('^lib','',lib)
	if lib=='m':
		return None
	(lt_path,lt_libname,lt_static)=self.find_lt_names_msvc(lib,is_static)
	if lt_path!=None and lt_libname!=None:
		if lt_static==True:
			return os.path.join(lt_path,lt_libname)
	if lt_path!=None:
		_libpaths=[lt_path]+self.env['LIBPATH']
	else:
		_libpaths=self.env['LIBPATH']
	static_libs=['lib%ss.lib'%lib,'lib%s.lib'%lib,'%ss.lib'%lib,'%s.lib'%lib,]
	dynamic_libs=['lib%s.dll.lib'%lib,'lib%s.dll.a'%lib,'%s.dll.lib'%lib,'%s.dll.a'%lib,'lib%s_d.lib'%lib,'%s_d.lib'%lib,'%s.lib'%lib,]
	libnames=static_libs
	if not is_static:
		libnames=dynamic_libs+static_libs
	for path in _libpaths:
		for libn in libnames:
			if os.path.exists(os.path.join(path,libn)):
				debug('msvc: lib found: %s'%os.path.join(path,libn))
				return re.sub('\.lib$','',libn)
	self.fatal("The library %r could not be found"%libname)
	return re.sub('\.lib$','',libname)
@conf
def check_lib_msvc(self,libname,is_static=False,uselib_store=None):
	libn=self.libname_msvc(libname,is_static)
	if not uselib_store:
		uselib_store=libname.upper()
	if False and is_static:
		self.env['STLIB_'+uselib_store]=[libn]
	else:
		self.env['LIB_'+uselib_store]=[libn]
@conf
def check_libs_msvc(self,libnames,is_static=False):
	for libname in Utils.to_list(libnames):
		self.check_lib_msvc(libname,is_static)
def configure(conf):
	conf.autodetect(True)
	conf.find_msvc()
	conf.msvc_common_flags()
	conf.cc_load_tools()
	conf.cxx_load_tools()
	conf.cc_add_flags()
	conf.cxx_add_flags()
	conf.link_add_flags()
	conf.visual_studio_add_flags()
@conf
def no_autodetect(conf):
	conf.env.NO_MSVC_DETECT=1
	configure(conf)
@conf
def autodetect(conf,arch=False):
	v=conf.env
	if v.NO_MSVC_DETECT:
		return
	if arch:
		compiler,version,path,includes,libdirs,arch=conf.detect_msvc(True)
		v['DEST_CPU']=arch
	else:
		compiler,version,path,includes,libdirs=conf.detect_msvc()
	v['PATH']=path
	v['INCLUDES']=includes
	v['LIBPATH']=libdirs
	v['MSVC_COMPILER']=compiler
	try:
		v['MSVC_VERSION']=float(version)
	except Exception:
		v['MSVC_VERSION']=float(version[:-3])
def _get_prog_names(conf,compiler):
	if compiler=='intel':
		compiler_name='ICL'
		linker_name='XILINK'
		lib_name='XILIB'
	else:
		compiler_name='CL'
		linker_name='LINK'
		lib_name='LIB'
	return compiler_name,linker_name,lib_name
@conf
def find_msvc(conf):
	if sys.platform=='cygwin':
		conf.fatal('MSVC module does not work under cygwin Python!')
	v=conf.env
	path=v['PATH']
	compiler=v['MSVC_COMPILER']
	version=v['MSVC_VERSION']
	compiler_name,linker_name,lib_name=_get_prog_names(conf,compiler)
	v.MSVC_MANIFEST=(compiler=='msvc'and version>=8)or(compiler=='wsdk'and version>=6)or(compiler=='intel'and version>=11)
	cxx=None
	if v['CXX']:cxx=v['CXX']
	elif'CXX'in conf.environ:cxx=conf.environ['CXX']
	cxx=conf.find_program(compiler_name,var='CXX',path_list=path)
	cxx=conf.cmd_to_list(cxx)
	env=dict(conf.environ)
	if path:env.update(PATH=';'.join(path))
	if not conf.cmd_and_log(cxx+['/nologo','/help'],env=env):
		conf.fatal('the msvc compiler could not be identified')
	v['CC']=v['CXX']=cxx
	v['CC_NAME']=v['CXX_NAME']='msvc'
	if not v['LINK_CXX']:
		link=conf.find_program(linker_name,path_list=path)
		if link:v['LINK_CXX']=link
		else:conf.fatal('%s was not found (linker)'%linker_name)
		v['LINK']=link
	if not v['LINK_CC']:
		v['LINK_CC']=v['LINK_CXX']
	if not v['AR']:
		stliblink=conf.find_program(lib_name,path_list=path,var='AR')
		if not stliblink:return
		v['ARFLAGS']=['/NOLOGO']
	if v.MSVC_MANIFEST:
		conf.find_program('MT',path_list=path,var='MT')
		v['MTFLAGS']=['/NOLOGO']
	try:
		conf.load('winres')
	except Errors.WafError:
		warn('Resource compiler not found. Compiling resource file is disabled')
@conf
def visual_studio_add_flags(self):
	v=self.env
	try:v.prepend_value('INCLUDES',[x for x in self.environ['INCLUDE'].split(';')if x])
	except Exception:pass
	try:v.prepend_value('LIBPATH',[x for x in self.environ['LIB'].split(';')if x])
	except Exception:pass
@conf
def msvc_common_flags(conf):
	v=conf.env
	v['DEST_BINFMT']='pe'
	v.append_value('CFLAGS',['/nologo'])
	v.append_value('CXXFLAGS',['/nologo'])
	v['DEFINES_ST']='/D%s'
	v['CC_SRC_F']=''
	v['CC_TGT_F']=['/c','/Fo']
	if v['MSVC_VERSION']>=8:
		v['CC_TGT_F']=['/FC']+v['CC_TGT_F']
	v['CXX_SRC_F']=''
	v['CXX_TGT_F']=['/c','/Fo']
	if v['MSVC_VERSION']>=8:
		v['CXX_TGT_F']=['/FC']+v['CXX_TGT_F']
	v['CPPPATH_ST']='/I%s'
	v['AR_TGT_F']=v['CCLNK_TGT_F']=v['CXXLNK_TGT_F']='/OUT:'
	v['CFLAGS_CONSOLE']=v['CXXFLAGS_CONSOLE']=['/SUBSYSTEM:CONSOLE']
	v['CFLAGS_NATIVE']=v['CXXFLAGS_NATIVE']=['/SUBSYSTEM:NATIVE']
	v['CFLAGS_POSIX']=v['CXXFLAGS_POSIX']=['/SUBSYSTEM:POSIX']
	v['CFLAGS_WINDOWS']=v['CXXFLAGS_WINDOWS']=['/SUBSYSTEM:WINDOWS']
	v['CFLAGS_WINDOWSCE']=v['CXXFLAGS_WINDOWSCE']=['/SUBSYSTEM:WINDOWSCE']
	v['CFLAGS_CRT_MULTITHREADED']=v['CXXFLAGS_CRT_MULTITHREADED']=['/MT']
	v['CFLAGS_CRT_MULTITHREADED_DLL']=v['CXXFLAGS_CRT_MULTITHREADED_DLL']=['/MD']
	v['CFLAGS_CRT_MULTITHREADED_DBG']=v['CXXFLAGS_CRT_MULTITHREADED_DBG']=['/MTd']
	v['CFLAGS_CRT_MULTITHREADED_DLL_DBG']=v['CXXFLAGS_CRT_MULTITHREADED_DLL_DBG']=['/MDd']
	v['LIB_ST']='%s.lib'
	v['LIBPATH_ST']='/LIBPATH:%s'
	v['STLIB_ST']='%s.lib'
	v['STLIBPATH_ST']='/LIBPATH:%s'
	v.append_value('LINKFLAGS',['/NOLOGO'])
	if v['MSVC_MANIFEST']:
		v.append_value('LINKFLAGS',['/MANIFEST'])
	v['CFLAGS_cshlib']=[]
	v['CXXFLAGS_cxxshlib']=[]
	v['LINKFLAGS_cshlib']=v['LINKFLAGS_cxxshlib']=['/DLL']
	v['cshlib_PATTERN']=v['cxxshlib_PATTERN']='%s.dll'
	v['implib_PATTERN']='%s.lib'
	v['IMPLIB_ST']='/IMPLIB:%s'
	v['LINKFLAGS_cstlib']=[]
	v['cstlib_PATTERN']=v['cxxstlib_PATTERN']='%s.lib'
	v['cprogram_PATTERN']=v['cxxprogram_PATTERN']='%s.exe'
@after_method('apply_link')
@feature('c','cxx')
def apply_flags_msvc(self):
	if self.env.CC_NAME!='msvc'or not getattr(self,'link_task',None):
		return
	is_static=isinstance(self.link_task,ccroot.stlink_task)
	subsystem=getattr(self,'subsystem','')
	if subsystem:
		subsystem='/subsystem:%s'%subsystem
		flags=is_static and'ARFLAGS'or'LINKFLAGS'
		self.env.append_value(flags,subsystem)
	if not is_static:
		for f in self.env.LINKFLAGS:
			d=f.lower()
			if d[1:]=='debug':
				pdbnode=self.link_task.outputs[0].change_ext('.pdb')
				self.link_task.outputs.append(pdbnode)
				try:
					self.install_task.source.append(pdbnode)
				except AttributeError:
					pass
				break
@feature('cprogram','cshlib','cxxprogram','cxxshlib')
@after_method('apply_link')
def apply_manifest(self):
	if self.env.CC_NAME=='msvc'and self.env.MSVC_MANIFEST and getattr(self,'link_task',None):
		out_node=self.link_task.outputs[0]
		man_node=out_node.parent.find_or_declare(out_node.name+'.manifest')
		self.link_task.outputs.append(man_node)
		self.link_task.do_manifest=True
def exec_mf(self):
	env=self.env
	mtool=env['MT']
	if not mtool:
		return 0
	self.do_manifest=False
	outfile=self.outputs[0].abspath()
	manifest=None
	for out_node in self.outputs:
		if out_node.name.endswith('.manifest'):
			manifest=out_node.abspath()
			break
	if manifest is None:
		return 0
	mode=''
	if'cprogram'in self.generator.features or'cxxprogram'in self.generator.features:
		mode='1'
	elif'cshlib'in self.generator.features or'cxxshlib'in self.generator.features:
		mode='2'
	debug('msvc: embedding manifest in mode %r'%mode)
	lst=[]
	lst.append(env['MT'])
	lst.extend(Utils.to_list(env['MTFLAGS']))
	lst.extend(['-manifest',manifest])
	lst.append('-outputresource:%s;%s'%(outfile,mode))
	lst=[lst]
	return self.exec_command(*lst)
def quote_response_command(self,flag):
	if flag.find(' ')>-1:
		for x in('/LIBPATH:','/IMPLIB:','/OUT:','/I'):
			if flag.startswith(x):
				flag='%s"%s"'%(x,flag[len(x):])
				break
		else:
			flag='"%s"'%flag
	return flag
def exec_response_command(self,cmd,**kw):
	try:
		tmp=None
		if sys.platform.startswith('win')and isinstance(cmd,list)and len(' '.join(cmd))>=8192:
			program=cmd[0]
			cmd=[self.quote_response_command(x)for x in cmd]
			(fd,tmp)=tempfile.mkstemp()
			os.write(fd,'\r\n'.join(i.replace('\\','\\\\')for i in cmd[1:]))
			os.close(fd)
			cmd=[program,'@'+tmp]
		ret=self.generator.bld.exec_command(cmd,**kw)
	finally:
		if tmp:
			try:
				os.remove(tmp)
			except OSError:
				pass
	return ret
def exec_command_msvc(self,*k,**kw):
	if isinstance(k[0],list):
		lst=[]
		carry=''
		for a in k[0]:
			if a=='/Fo'or a=='/doc'or a[-1]==':':
				carry=a
			else:
				lst.append(carry+a)
				carry=''
		k=[lst]
	if self.env['PATH']:
		env=dict(self.env.env or os.environ)
		env.update(PATH=';'.join(self.env['PATH']))
		kw['env']=env
	bld=self.generator.bld
	try:
		if not kw.get('cwd',None):
			kw['cwd']=bld.cwd
	except AttributeError:
		bld.cwd=kw['cwd']=bld.variant_dir
	ret=self.exec_response_command(k[0],**kw)
	if not ret and getattr(self,'do_manifest',None):
		ret=self.exec_mf()
	return ret
def wrap_class(class_name):
	cls=Task.classes.get(class_name,None)
	if not cls:
		return None
	derived_class=type(class_name,(cls,),{})
	def exec_command(self,*k,**kw):
		if self.env['CC_NAME']=='msvc':
			return self.exec_command_msvc(*k,**kw)
		else:
			return super(derived_class,self).exec_command(*k,**kw)
	derived_class.exec_command=exec_command
	derived_class.exec_response_command=exec_response_command
	derived_class.quote_response_command=quote_response_command
	derived_class.exec_command_msvc=exec_command_msvc
	derived_class.exec_mf=exec_mf
	return derived_class
for k in'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split():
	wrap_class(k)
def make_winapp(self,family):
	append=self.env.append_unique
	append('DEFINES','WINAPI_FAMILY=%s'%family)
	append('CXXFLAGS','/ZW')
	append('CXXFLAGS','/TP')
	for lib_path in self.env.LIBPATH:
		append('CXXFLAGS','/AI%s'%lib_path)
@feature('winphoneapp')
@after_method('process_use')
@after_method('propagate_uselib_vars')
def make_winphone_app(self):
	make_winapp(self,'WINAPI_FAMILY_PHONE_APP')
	conf.env.append_unique('LINKFLAGS','/NODEFAULTLIB:ole32.lib')
	conf.env.append_unique('LINKFLAGS','PhoneAppModelHost.lib')
@feature('winapp')
@after_method('process_use')
@after_method('propagate_uselib_vars')
def make_windows_app(self):
	make_winapp(self,'WINAPI_FAMILY_DESKTOP_APP')
