mirror of https://gitlab.com/ita1024/waf.git
Merge branch 'MSVCRefactor' into 'waf-2.1'
Split msvc module into msvc_common and msvc See merge request ita1024/waf!2272
This commit is contained in:
commit
edfaa0a4c0
|
@ -8,7 +8,9 @@ build
|
||||||
demos/*/build*
|
demos/*/build*
|
||||||
playground/*/build*
|
playground/*/build*
|
||||||
.waf-*
|
.waf-*
|
||||||
|
waf-*
|
||||||
.waf3-*
|
.waf3-*
|
||||||
|
waf3-*
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.AppleDouble
|
.AppleDouble
|
||||||
|
@ -37,3 +39,9 @@ Temporary Items
|
||||||
|
|
||||||
# Windows build output
|
# Windows build output
|
||||||
waf.bat
|
waf.bat
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# YouCompleteMe configuration
|
||||||
|
.ycm_extra_conf.py
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
puts("This is a simple test program.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
top = '.'
|
||||||
|
out = 'build'
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
opt.load('msvc')
|
||||||
|
|
||||||
|
def configure(cfg):
|
||||||
|
cfg.load('msvc')
|
||||||
|
cfg.load('msvc_pdb')
|
||||||
|
cfg.env.append_value('CFLAGS','/Zi')
|
||||||
|
cfg.env.append_value('LDFLAGS','/DEBUG')
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
bld.program(
|
||||||
|
name='test',
|
||||||
|
source=['test.c'],
|
||||||
|
target='test',
|
||||||
|
use='CRT_MULTITHREADED_DLL')
|
|
@ -55,366 +55,14 @@ cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure"
|
||||||
Setting PYTHONUNBUFFERED gives the unbuffered output.
|
Setting PYTHONUNBUFFERED gives the unbuffered output.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, sys, re, traceback
|
import os, re
|
||||||
from waflib import Utils, Logs, Options, Errors
|
from waflib import Utils, Logs
|
||||||
from waflib.TaskGen import after_method, feature
|
|
||||||
|
|
||||||
from waflib.Configure import conf
|
from waflib.Configure import conf
|
||||||
from waflib.Tools import ccroot, c, cxx, ar
|
from waflib.Tools import ccroot, c, cxx, ar, msvc_common
|
||||||
|
|
||||||
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()
|
|
||||||
"""importlibs provided by MSVC/Platform SDK. Do NOT search them"""
|
|
||||||
|
|
||||||
all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'),
|
|
||||||
('x86_amd64', 'amd64'), ('x86_ia64', 'ia64'), ('x86_arm', 'arm'), ('x86_arm64', 'arm64'),
|
|
||||||
('amd64_x86', 'x86'), ('amd64_arm', 'arm'), ('amd64_arm64', 'arm64') ]
|
|
||||||
"""List of msvc platforms"""
|
|
||||||
|
|
||||||
all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')]
|
|
||||||
"""List of icl platforms"""
|
|
||||||
|
|
||||||
def options(opt):
|
def options(opt):
|
||||||
opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='')
|
msvc_common.options(opt)
|
||||||
opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='')
|
|
||||||
opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy')
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def setup_msvc(conf, versiondict):
|
|
||||||
"""
|
|
||||||
Checks installed compilers and targets and returns the first combination from the user's
|
|
||||||
options, env, or the global supported lists that checks.
|
|
||||||
|
|
||||||
:param versiondict: dict(platform -> dict(architecture -> configuration))
|
|
||||||
:type versiondict: dict(string -> dict(string -> target_compiler)
|
|
||||||
:return: the compiler, revision, path, include dirs, library paths and 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]
|
|
||||||
desired_versions = getattr(Options.options, 'msvc_version', '').split(',')
|
|
||||||
if desired_versions == ['']:
|
|
||||||
desired_versions = conf.env.MSVC_VERSIONS or list(reversed(sorted(versiondict.keys())))
|
|
||||||
|
|
||||||
# Override lazy detection by evaluating after the fact.
|
|
||||||
lazy_detect = getattr(Options.options, 'msvc_lazy', True)
|
|
||||||
if conf.env.MSVC_LAZY_AUTODETECT is False:
|
|
||||||
lazy_detect = False
|
|
||||||
|
|
||||||
if not lazy_detect:
|
|
||||||
for val in versiondict.values():
|
|
||||||
for arch in list(val.keys()):
|
|
||||||
cfg = val[arch]
|
|
||||||
cfg.evaluate()
|
|
||||||
if not cfg.is_valid:
|
|
||||||
del val[arch]
|
|
||||||
conf.env.MSVC_INSTALLED_VERSIONS = versiondict
|
|
||||||
|
|
||||||
for version in desired_versions:
|
|
||||||
Logs.debug('msvc: detecting %r - %r', version, desired_versions)
|
|
||||||
try:
|
|
||||||
targets = versiondict[version]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
seen = set()
|
|
||||||
for arch in platforms:
|
|
||||||
if arch in seen:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
seen.add(arch)
|
|
||||||
try:
|
|
||||||
cfg = targets[arch]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
cfg.evaluate()
|
|
||||||
if cfg.is_valid:
|
|
||||||
compiler,revision = version.rsplit(' ', 1)
|
|
||||||
return compiler,revision,cfg.bindirs,cfg.incdirs,cfg.libdirs,cfg.cpu
|
|
||||||
conf.fatal('msvc: Impossible to find a valid architecture for building %r - %r' % (desired_versions, list(versiondict.keys())))
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def get_msvc_version(conf, compiler, version, target, vcvars):
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
|
|
||||||
|
|
||||||
try:
|
|
||||||
conf.msvc_cnt += 1
|
|
||||||
except AttributeError:
|
|
||||||
conf.msvc_cnt = 1
|
|
||||||
batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt)
|
|
||||||
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.exe', '/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)')
|
|
||||||
|
|
||||||
# Check if the compiler is usable at all.
|
|
||||||
# The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.
|
|
||||||
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)
|
|
||||||
|
|
||||||
# delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically.
|
|
||||||
if 'CL' in env:
|
|
||||||
del(env['CL'])
|
|
||||||
|
|
||||||
try:
|
|
||||||
conf.cmd_and_log(cxx + ['/help'], env=env)
|
|
||||||
except UnicodeError:
|
|
||||||
st = traceback.format_exc()
|
|
||||||
if conf.logger:
|
|
||||||
conf.logger.error(st)
|
|
||||||
conf.fatal('msvc: Unicode error - check the code page?')
|
|
||||||
except Exception as e:
|
|
||||||
Logs.debug('msvc: get_msvc_version: %r %r %r -> failure %s', compiler, version, target, str(e))
|
|
||||||
conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)')
|
|
||||||
else:
|
|
||||||
Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
|
|
||||||
finally:
|
|
||||||
conf.env[compiler_name] = ''
|
|
||||||
|
|
||||||
return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)
|
|
||||||
|
|
||||||
def gather_msvc_detected_versions():
|
|
||||||
#Detected MSVC versions!
|
|
||||||
version_pattern = re.compile(r'^(\d\d?\.\d\d?)(Exp)?$')
|
|
||||||
detected_versions = []
|
|
||||||
for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')):
|
|
||||||
prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver
|
|
||||||
try:
|
|
||||||
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)
|
|
||||||
except OSError:
|
|
||||||
prefix = 'SOFTWARE\\Microsoft\\' + vcver
|
|
||||||
try:
|
|
||||||
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
index = 0
|
|
||||||
while 1:
|
|
||||||
try:
|
|
||||||
version = Utils.winreg.EnumKey(all_versions, index)
|
|
||||||
except OSError:
|
|
||||||
break
|
|
||||||
index += 1
|
|
||||||
match = version_pattern.match(version)
|
|
||||||
if match:
|
|
||||||
versionnumber = float(match.group(1))
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
detected_versions.append((versionnumber, version+vcvar, prefix+'\\'+version))
|
|
||||||
def fun(tup):
|
|
||||||
return tup[0]
|
|
||||||
|
|
||||||
detected_versions.sort(key = fun)
|
|
||||||
return detected_versions
|
|
||||||
|
|
||||||
class target_compiler(object):
|
|
||||||
"""
|
|
||||||
Wrap a compiler configuration; call evaluate() to determine
|
|
||||||
whether the configuration is usable.
|
|
||||||
"""
|
|
||||||
def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None):
|
|
||||||
"""
|
|
||||||
:param ctx: configuration context to use to eventually get the version environment
|
|
||||||
:param compiler: compiler name
|
|
||||||
:param cpu: target cpu
|
|
||||||
:param version: compiler version number
|
|
||||||
:param bat_target: ?
|
|
||||||
:param bat: path to the batch file to run
|
|
||||||
"""
|
|
||||||
self.conf = ctx
|
|
||||||
self.name = None
|
|
||||||
self.is_valid = False
|
|
||||||
self.is_done = False
|
|
||||||
|
|
||||||
self.compiler = compiler
|
|
||||||
self.cpu = cpu
|
|
||||||
self.version = version
|
|
||||||
self.bat_target = bat_target
|
|
||||||
self.bat = bat
|
|
||||||
self.callback = callback
|
|
||||||
|
|
||||||
def evaluate(self):
|
|
||||||
if self.is_done:
|
|
||||||
return
|
|
||||||
self.is_done = True
|
|
||||||
try:
|
|
||||||
vs = self.conf.get_msvc_version(self.compiler, self.version, self.bat_target, self.bat)
|
|
||||||
except Errors.ConfigurationError:
|
|
||||||
self.is_valid = False
|
|
||||||
return
|
|
||||||
if self.callback:
|
|
||||||
vs = self.callback(self, vs)
|
|
||||||
self.is_valid = True
|
|
||||||
(self.bindirs, self.incdirs, self.libdirs) = vs
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str((self.compiler, self.cpu, self.version, self.bat_target, self.bat))
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return repr((self.compiler, self.cpu, self.version, self.bat_target, self.bat))
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def gather_wsdk_versions(conf, versions):
|
|
||||||
"""
|
|
||||||
Use winreg to add the msvc versions to the input list
|
|
||||||
|
|
||||||
:param versions: list to modify
|
|
||||||
:type versions: list
|
|
||||||
"""
|
|
||||||
version_pattern = re.compile(r'^v..?.?\...?.?')
|
|
||||||
try:
|
|
||||||
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
|
|
||||||
except OSError:
|
|
||||||
try:
|
|
||||||
all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
|
|
||||||
except OSError:
|
|
||||||
return
|
|
||||||
index = 0
|
|
||||||
while 1:
|
|
||||||
try:
|
|
||||||
version = Utils.winreg.EnumKey(all_versions, index)
|
|
||||||
except OSError:
|
|
||||||
break
|
|
||||||
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 OSError:
|
|
||||||
continue
|
|
||||||
if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
|
|
||||||
targets = {}
|
|
||||||
for target,arch in all_msvc_platforms:
|
|
||||||
targets[target] = target_compiler(conf, 'wsdk', arch, version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd'))
|
|
||||||
versions['wsdk ' + version[1:]] = targets
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def gather_msvc_targets(conf, versions, version, vc_path):
|
|
||||||
#Looking for normal MSVC compilers!
|
|
||||||
targets = {}
|
|
||||||
|
|
||||||
if os.path.isfile(os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')):
|
|
||||||
for target,realtarget in all_msvc_platforms[::-1]:
|
|
||||||
targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat'))
|
|
||||||
elif os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
|
|
||||||
for target,realtarget in all_msvc_platforms[::-1]:
|
|
||||||
targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'vcvarsall.bat'))
|
|
||||||
elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):
|
|
||||||
targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat'))
|
|
||||||
elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):
|
|
||||||
targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat'))
|
|
||||||
if targets:
|
|
||||||
versions['msvc %s' % version] = targets
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def gather_vswhere_versions(conf, versions):
|
|
||||||
try:
|
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
Logs.error('Visual Studio 2017 detection requires Python 2.6')
|
|
||||||
return
|
|
||||||
|
|
||||||
prg_path = os.environ.get('ProgramFiles(x86)', os.environ.get('ProgramFiles', 'C:\\Program Files (x86)'))
|
|
||||||
|
|
||||||
vswhere = os.path.join(prg_path, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
|
|
||||||
args = [vswhere, '-products', '*', '-legacy', '-format', 'json']
|
|
||||||
try:
|
|
||||||
txt = conf.cmd_and_log(args)
|
|
||||||
except Errors.WafError as e:
|
|
||||||
Logs.debug('msvc: vswhere.exe failed %s', e)
|
|
||||||
return
|
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
|
||||||
txt = txt.decode(Utils.console_encoding())
|
|
||||||
|
|
||||||
arr = json.loads(txt)
|
|
||||||
arr.sort(key=lambda x: x['installationVersion'])
|
|
||||||
for entry in arr:
|
|
||||||
ver = entry['installationVersion']
|
|
||||||
ver = str('.'.join(ver.split('.')[:2]))
|
|
||||||
path = str(os.path.abspath(entry['installationPath']))
|
|
||||||
if os.path.exists(path) and ('msvc %s' % ver) not in versions:
|
|
||||||
conf.gather_msvc_targets(versions, ver, path)
|
|
||||||
|
|
||||||
@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 OSError:
|
|
||||||
msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++")
|
|
||||||
path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir')
|
|
||||||
except OSError:
|
|
||||||
try:
|
|
||||||
msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432node\\Microsoft\\VisualStudio\\SxS\\VS7")
|
|
||||||
path,type = Utils.winreg.QueryValueEx(msvc_version, version)
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
vc_paths.append((version, os.path.abspath(str(path))))
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
vc_paths.append((version, os.path.abspath(str(path))))
|
|
||||||
|
|
||||||
for version,vc_path in vc_paths:
|
|
||||||
conf.gather_msvc_targets(versions, version, vc_path)
|
|
||||||
|
|
||||||
@conf
|
@conf
|
||||||
def gather_icl_versions(conf, versions):
|
def gather_icl_versions(conf, versions):
|
||||||
|
@ -442,7 +90,7 @@ def gather_icl_versions(conf, versions):
|
||||||
if not version_pattern.match(version):
|
if not version_pattern.match(version):
|
||||||
continue
|
continue
|
||||||
targets = {}
|
targets = {}
|
||||||
for target,arch in all_icl_platforms:
|
for target,arch in msvc_common.all_icl_platforms:
|
||||||
if target=='intel64':
|
if target=='intel64':
|
||||||
targetDir='EM64T_NATIVE'
|
targetDir='EM64T_NATIVE'
|
||||||
else:
|
else:
|
||||||
|
@ -457,7 +105,7 @@ def gather_icl_versions(conf, versions):
|
||||||
batch_file=os.path.join(path,'bin','iclvars.bat')
|
batch_file=os.path.join(path,'bin','iclvars.bat')
|
||||||
if os.path.isfile(batch_file):
|
if os.path.isfile(batch_file):
|
||||||
targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
|
targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file)
|
||||||
for target,arch in all_icl_platforms:
|
for target,arch in msvc_common.all_icl_platforms:
|
||||||
try:
|
try:
|
||||||
icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target)
|
icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target)
|
||||||
path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir')
|
path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir')
|
||||||
|
@ -496,7 +144,7 @@ def gather_intel_composer_versions(conf, versions):
|
||||||
if not version_pattern.match(version):
|
if not version_pattern.match(version):
|
||||||
continue
|
continue
|
||||||
targets = {}
|
targets = {}
|
||||||
for target,arch in all_icl_platforms:
|
for target,arch in msvc_common.all_icl_platforms:
|
||||||
if target=='intel64':
|
if target=='intel64':
|
||||||
targetDir='EM64T_NATIVE'
|
targetDir='EM64T_NATIVE'
|
||||||
else:
|
else:
|
||||||
|
@ -540,11 +188,7 @@ def gather_intel_composer_versions(conf, versions):
|
||||||
versions['intel ' + major] = targets
|
versions['intel ' + major] = targets
|
||||||
|
|
||||||
@conf
|
@conf
|
||||||
def detect_msvc(self):
|
def get_icl_versions(self):
|
||||||
return self.setup_msvc(self.get_msvc_versions())
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def get_msvc_versions(self):
|
|
||||||
"""
|
"""
|
||||||
:return: platform to compiler configurations
|
:return: platform to compiler configurations
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
|
@ -552,133 +196,13 @@ def get_msvc_versions(self):
|
||||||
dct = Utils.ordered_iter_dict()
|
dct = Utils.ordered_iter_dict()
|
||||||
self.gather_icl_versions(dct)
|
self.gather_icl_versions(dct)
|
||||||
self.gather_intel_composer_versions(dct)
|
self.gather_intel_composer_versions(dct)
|
||||||
self.gather_wsdk_versions(dct)
|
|
||||||
self.gather_msvc_versions(dct)
|
|
||||||
self.gather_vswhere_versions(dct)
|
|
||||||
Logs.debug('msvc: detected versions %r', list(dct.keys()))
|
|
||||||
return dct
|
return dct
|
||||||
|
|
||||||
@conf
|
|
||||||
def find_lt_names_msvc(self, libname, is_static=False):
|
|
||||||
"""
|
|
||||||
Win32/MSVC specific code to glean out information from libtool la files.
|
|
||||||
this function is not attached to the task_gen class. Returns a triplet:
|
|
||||||
(library absolute path, library name without extension, whether the library is static)
|
|
||||||
"""
|
|
||||||
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(r'\.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(r'\.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:
|
|
||||||
# file existence check has been made by find_lt_names
|
|
||||||
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)):
|
|
||||||
Logs.debug('msvc: lib found: %s', os.path.join(path,libn))
|
|
||||||
return re.sub(r'\.lib$', '',libn)
|
|
||||||
|
|
||||||
#if no lib can be found, just return the libname as msvc expects it
|
|
||||||
self.fatal('The library %r could not be found' % libname)
|
|
||||||
return re.sub(r'\.lib$', '', libname)
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def check_lib_msvc(self, libname, is_static=False, uselib_store=None):
|
|
||||||
"""
|
|
||||||
Ideally we should be able to place the lib in the right env var, either STLIB or LIB,
|
|
||||||
but we don't distinguish static libs from shared libs.
|
|
||||||
This is ok since msvc doesn't have any special linker flag to select static libs (no env.STLIB_MARKER)
|
|
||||||
"""
|
|
||||||
libn = self.libname_msvc(libname, is_static)
|
|
||||||
|
|
||||||
if not uselib_store:
|
|
||||||
uselib_store = libname.upper()
|
|
||||||
|
|
||||||
if False and is_static: # disabled
|
|
||||||
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):
|
def configure(conf):
|
||||||
"""
|
"""
|
||||||
Configuration methods to call for detecting msvc
|
Configuration methods to call for detecting msvc
|
||||||
"""
|
"""
|
||||||
conf.autodetect(True)
|
conf.autodetect(True, get_icl_versions)
|
||||||
conf.find_msvc()
|
conf.find_msvc()
|
||||||
conf.msvc_common_flags()
|
conf.msvc_common_flags()
|
||||||
conf.cc_load_tools()
|
conf.cc_load_tools()
|
||||||
|
@ -692,203 +216,3 @@ def configure(conf):
|
||||||
def no_autodetect(conf):
|
def no_autodetect(conf):
|
||||||
conf.env.NO_MSVC_DETECT = 1
|
conf.env.NO_MSVC_DETECT = 1
|
||||||
configure(conf)
|
configure(conf)
|
||||||
|
|
||||||
@conf
|
|
||||||
def autodetect(conf, arch=False):
|
|
||||||
v = conf.env
|
|
||||||
if v.NO_MSVC_DETECT:
|
|
||||||
return
|
|
||||||
|
|
||||||
compiler, version, path, includes, libdirs, cpu = conf.detect_msvc()
|
|
||||||
if arch:
|
|
||||||
v.DEST_CPU = cpu
|
|
||||||
|
|
||||||
v.PATH = path
|
|
||||||
v.INCLUDES = includes
|
|
||||||
v.LIBPATH = libdirs
|
|
||||||
v.MSVC_COMPILER = compiler
|
|
||||||
try:
|
|
||||||
v.MSVC_VERSION = float(version)
|
|
||||||
except ValueError:
|
|
||||||
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:
|
|
||||||
# assumes CL.exe
|
|
||||||
compiler_name = 'CL'
|
|
||||||
linker_name = 'LINK'
|
|
||||||
lib_name = 'LIB'
|
|
||||||
return compiler_name, linker_name, lib_name
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def find_msvc(conf):
|
|
||||||
"""Due to path format limitations, limit operation only to native Win32. Yeah it sucks."""
|
|
||||||
if sys.platform == 'cygwin':
|
|
||||||
conf.fatal('MSVC module does not work under cygwin Python!')
|
|
||||||
|
|
||||||
# the autodetection is supposed to be performed before entering in this method
|
|
||||||
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)
|
|
||||||
|
|
||||||
# compiler
|
|
||||||
cxx = conf.find_program(compiler_name, var='CXX', path_list=path)
|
|
||||||
|
|
||||||
# before setting anything, check if the compiler is really msvc
|
|
||||||
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')
|
|
||||||
|
|
||||||
# c/c++ compiler
|
|
||||||
v.CC = v.CXX = cxx
|
|
||||||
v.CC_NAME = v.CXX_NAME = 'msvc'
|
|
||||||
|
|
||||||
# linker
|
|
||||||
if not v.LINK_CXX:
|
|
||||||
conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX')
|
|
||||||
|
|
||||||
if not v.LINK_CC:
|
|
||||||
v.LINK_CC = v.LINK_CXX
|
|
||||||
|
|
||||||
# staticlib linker
|
|
||||||
if not v.AR:
|
|
||||||
stliblink = conf.find_program(lib_name, path_list=path, var='AR')
|
|
||||||
if not stliblink:
|
|
||||||
return
|
|
||||||
v.ARFLAGS = ['/nologo']
|
|
||||||
|
|
||||||
# manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
|
|
||||||
if v.MSVC_MANIFEST:
|
|
||||||
conf.find_program('MT', path_list=path, var='MT')
|
|
||||||
v.MTFLAGS = ['/nologo']
|
|
||||||
|
|
||||||
try:
|
|
||||||
conf.load('winres')
|
|
||||||
except Errors.ConfigurationError:
|
|
||||||
Logs.warn('Resource compiler not found. Compiling resource file is disabled')
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def visual_studio_add_flags(self):
|
|
||||||
"""visual studio flags found in the system environment"""
|
|
||||||
v = self.env
|
|
||||||
if self.environ.get('INCLUDE'):
|
|
||||||
v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S'
|
|
||||||
if self.environ.get('LIB'):
|
|
||||||
v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x])
|
|
||||||
|
|
||||||
@conf
|
|
||||||
def msvc_common_flags(conf):
|
|
||||||
"""
|
|
||||||
Setup the flags required for executing the msvc compiler
|
|
||||||
"""
|
|
||||||
v = conf.env
|
|
||||||
|
|
||||||
v.DEST_BINFMT = 'pe'
|
|
||||||
v.append_value('CFLAGS', ['/nologo'])
|
|
||||||
v.append_value('CXXFLAGS', ['/nologo'])
|
|
||||||
v.append_value('LINKFLAGS', ['/nologo'])
|
|
||||||
v.DEFINES_ST = '/D%s'
|
|
||||||
|
|
||||||
v.CC_SRC_F = ''
|
|
||||||
v.CC_TGT_F = ['/c', '/Fo']
|
|
||||||
v.CXX_SRC_F = ''
|
|
||||||
v.CXX_TGT_F = ['/c', '/Fo']
|
|
||||||
|
|
||||||
if (v.MSVC_COMPILER == 'msvc' and v.MSVC_VERSION >= 8) or (v.MSVC_COMPILER == 'wsdk' and v.MSVC_VERSION >= 6):
|
|
||||||
v.CC_TGT_F = ['/FC'] + v.CC_TGT_F
|
|
||||||
v.CXX_TGT_F = ['/FC'] + v.CXX_TGT_F
|
|
||||||
|
|
||||||
v.CPPPATH_ST = '/I%s' # template for adding include paths
|
|
||||||
|
|
||||||
v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:'
|
|
||||||
|
|
||||||
# CRT specific flags
|
|
||||||
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'
|
|
||||||
|
|
||||||
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'
|
|
||||||
|
|
||||||
v.def_PATTERN = '/def:%s'
|
|
||||||
|
|
||||||
|
|
||||||
#######################################################################################################
|
|
||||||
##### conf above, build below
|
|
||||||
|
|
||||||
@after_method('apply_link')
|
|
||||||
@feature('c', 'cxx')
|
|
||||||
def apply_flags_msvc(self):
|
|
||||||
"""
|
|
||||||
Add additional flags implied by msvc, such as subsystems and pdb files::
|
|
||||||
|
|
||||||
def build(bld):
|
|
||||||
bld.stlib(source='main.c', target='bar', subsystem='gruik')
|
|
||||||
"""
|
|
||||||
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:] in ('debug', 'debug:full', 'debug:fastlink'):
|
|
||||||
pdbnode = self.link_task.outputs[0].change_ext('.pdb')
|
|
||||||
self.link_task.outputs.append(pdbnode)
|
|
||||||
|
|
||||||
if getattr(self, 'install_task', None):
|
|
||||||
self.pdb_install_task = self.add_install_files(
|
|
||||||
install_to=self.install_task.install_to, install_from=pdbnode)
|
|
||||||
break
|
|
||||||
|
|
||||||
@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib')
|
|
||||||
@after_method('apply_link')
|
|
||||||
def apply_manifest(self):
|
|
||||||
"""
|
|
||||||
Special linker for MSVC with support for embedding manifests into DLL's
|
|
||||||
and executables compiled by Visual Studio 2005 or probably later. Without
|
|
||||||
the manifest file, the binaries are unusable.
|
|
||||||
See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
|
|
||||||
"""
|
|
||||||
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.env.DO_MANIFEST = True
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,841 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
# Rafaël Kooi, 2019
|
||||||
|
|
||||||
|
"""
|
||||||
|
Reusable routines earlier found in msvc.py that are reused by
|
||||||
|
Tools/extra/clang_cl.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os, sys, re, traceback
|
||||||
|
from waflib import Utils, Logs, Options, Errors
|
||||||
|
from waflib.TaskGen import after_method, feature
|
||||||
|
|
||||||
|
from waflib.Configure import conf
|
||||||
|
from waflib.Tools import ccroot, c, cxx, ar
|
||||||
|
|
||||||
|
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()
|
||||||
|
"""importlibs provided by MSVC/Platform SDK. Do NOT search them"""
|
||||||
|
|
||||||
|
all_msvc_platforms = [
|
||||||
|
('x64', 'amd64'),
|
||||||
|
('x86', 'x86'),
|
||||||
|
('ia64', 'ia64'),
|
||||||
|
('x86_amd64', 'amd64'),
|
||||||
|
('x86_ia64', 'ia64'),
|
||||||
|
('x86_arm', 'arm'),
|
||||||
|
('x86_arm64', 'arm64'),
|
||||||
|
('amd64_x86', 'x86'),
|
||||||
|
('amd64_arm', 'arm'),
|
||||||
|
('amd64_arm64', 'arm64')
|
||||||
|
]
|
||||||
|
"""List of msvc platforms"""
|
||||||
|
|
||||||
|
all_icl_platforms = [
|
||||||
|
('intel64', 'amd64'),
|
||||||
|
('em64t', 'amd64'),
|
||||||
|
('ia32', 'x86'),
|
||||||
|
('Itanium', 'ia64')
|
||||||
|
]
|
||||||
|
"""List of icl platforms"""
|
||||||
|
|
||||||
|
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( \
|
||||||
|
'--no-msvc-lazy', \
|
||||||
|
action='store_false', \
|
||||||
|
help = 'lazily check msvc target environments', \
|
||||||
|
default=True, \
|
||||||
|
dest='msvc_lazy')
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def gather_wsdk_versions(conf, versions):
|
||||||
|
"""
|
||||||
|
Use winreg to add the msvc versions to the input list
|
||||||
|
|
||||||
|
:param versions: list to modify
|
||||||
|
:type versions: list
|
||||||
|
"""
|
||||||
|
version_pattern = re.compile(r'^v..?.?\...?.?')
|
||||||
|
try:
|
||||||
|
all_versions = Utils.winreg.OpenKey( \
|
||||||
|
Utils.winreg.HKEY_LOCAL_MACHINE, \
|
||||||
|
'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
|
||||||
|
except OSError:
|
||||||
|
try:
|
||||||
|
all_versions = Utils.winreg.OpenKey( \
|
||||||
|
Utils.winreg.HKEY_LOCAL_MACHINE, \
|
||||||
|
'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
|
||||||
|
except OSError:
|
||||||
|
return
|
||||||
|
|
||||||
|
index = 0
|
||||||
|
while 1:
|
||||||
|
try:
|
||||||
|
version = Utils.winreg.EnumKey(all_versions, index)
|
||||||
|
except OSError:
|
||||||
|
break
|
||||||
|
|
||||||
|
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 OSError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
|
||||||
|
targets = {}
|
||||||
|
for target,arch in all_msvc_platforms:
|
||||||
|
targets[target] = target_compiler( \
|
||||||
|
conf, \
|
||||||
|
'wsdk', \
|
||||||
|
arch, \
|
||||||
|
version, \
|
||||||
|
'/' + target, \
|
||||||
|
os.path.join(path, 'bin', 'SetEnv.cmd'))
|
||||||
|
|
||||||
|
versions['wsdk ' + version[1:]] = targets
|
||||||
|
|
||||||
|
def gather_msvc_detected_versions():
|
||||||
|
#Detected MSVC versions!
|
||||||
|
version_pattern = re.compile(r'^(\d\d?\.\d\d?)(Exp)?$')
|
||||||
|
detected_versions = []
|
||||||
|
for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')):
|
||||||
|
prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver
|
||||||
|
try:
|
||||||
|
all_versions = Utils.winreg.OpenKey( \
|
||||||
|
Utils.winreg.HKEY_LOCAL_MACHINE, \
|
||||||
|
prefix)
|
||||||
|
except OSError:
|
||||||
|
prefix = 'SOFTWARE\\Microsoft\\' + vcver
|
||||||
|
try:
|
||||||
|
all_versions = Utils.winreg.OpenKey( \
|
||||||
|
Utils.winreg.HKEY_LOCAL_MACHINE, \
|
||||||
|
prefix)
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
index = 0
|
||||||
|
while 1:
|
||||||
|
try:
|
||||||
|
version = Utils.winreg.EnumKey(all_versions, index)
|
||||||
|
except OSError:
|
||||||
|
break
|
||||||
|
|
||||||
|
index += 1
|
||||||
|
match = version_pattern.match(version)
|
||||||
|
if match:
|
||||||
|
versionnumber = float(match.group(1))
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
detected_versions.append( \
|
||||||
|
(versionnumber, version + vcvar, prefix + '\\' + version))
|
||||||
|
|
||||||
|
def fun(tup):
|
||||||
|
return tup[0]
|
||||||
|
|
||||||
|
detected_versions.sort(key = fun)
|
||||||
|
return detected_versions
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def get_msvc_version(conf, compiler, version, target, vcvars):
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
|
||||||
|
|
||||||
|
try:
|
||||||
|
conf.msvc_cnt += 1
|
||||||
|
except AttributeError:
|
||||||
|
conf.msvc_cnt = 1
|
||||||
|
batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt)
|
||||||
|
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.exe', '/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)')
|
||||||
|
|
||||||
|
# Check if the compiler is usable at all.
|
||||||
|
# The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.
|
||||||
|
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)
|
||||||
|
|
||||||
|
# delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically.
|
||||||
|
if 'CL' in env:
|
||||||
|
del(env['CL'])
|
||||||
|
|
||||||
|
try:
|
||||||
|
conf.cmd_and_log(cxx + ['/help'], env=env)
|
||||||
|
except UnicodeError:
|
||||||
|
st = traceback.format_exc()
|
||||||
|
if conf.logger:
|
||||||
|
conf.logger.error(st)
|
||||||
|
conf.fatal('msvc: Unicode error - check the code page?')
|
||||||
|
except Exception as e:
|
||||||
|
Logs.debug('msvc: get_msvc_version: %r %r %r -> failure %s', compiler, version, target, str(e))
|
||||||
|
conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)')
|
||||||
|
else:
|
||||||
|
Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
|
||||||
|
finally:
|
||||||
|
conf.env[compiler_name] = ''
|
||||||
|
|
||||||
|
return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)
|
||||||
|
|
||||||
|
class target_compiler(object):
|
||||||
|
"""
|
||||||
|
Wrap a compiler configuration; call evaluate() to determine
|
||||||
|
whether the configuration is usable.
|
||||||
|
"""
|
||||||
|
def __init__( \
|
||||||
|
self, \
|
||||||
|
ctx, \
|
||||||
|
compiler, \
|
||||||
|
cpu, \
|
||||||
|
version, \
|
||||||
|
bat_target, \
|
||||||
|
bat, \
|
||||||
|
callback=None):
|
||||||
|
"""
|
||||||
|
:param ctx: configuration context to use to eventually get the version environment
|
||||||
|
:param compiler: compiler name
|
||||||
|
:param cpu: target cpu
|
||||||
|
:param version: compiler version number
|
||||||
|
:param bat_target: ?
|
||||||
|
:param bat: path to the batch file to run
|
||||||
|
"""
|
||||||
|
self.conf = ctx
|
||||||
|
self.name = None
|
||||||
|
self.is_valid = False
|
||||||
|
self.is_done = False
|
||||||
|
|
||||||
|
self.compiler = compiler
|
||||||
|
self.cpu = cpu
|
||||||
|
self.version = version
|
||||||
|
self.bat_target = bat_target
|
||||||
|
self.bat = bat
|
||||||
|
self.callback = callback
|
||||||
|
|
||||||
|
def evaluate(self):
|
||||||
|
if self.is_done:
|
||||||
|
return
|
||||||
|
self.is_done = True
|
||||||
|
try:
|
||||||
|
vs = self.conf.get_msvc_version( \
|
||||||
|
self.compiler, \
|
||||||
|
self.version, \
|
||||||
|
self.bat_target, \
|
||||||
|
self.bat)
|
||||||
|
except Errors.ConfigurationError:
|
||||||
|
self.is_valid = False
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.callback:
|
||||||
|
vs = self.callback(self, vs)
|
||||||
|
|
||||||
|
self.is_valid = True
|
||||||
|
(self.bindirs, self.incdirs, self.libdirs) = vs
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str( \
|
||||||
|
(self.compiler, self.cpu, self.version, self.bat_target, self.bat))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return repr( \
|
||||||
|
(self.compiler, self.cpu, self.version, self.bat_target, self.bat))
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def gather_msvc_targets(conf, versions, version, vc_path):
|
||||||
|
#Looking for normal MSVC compilers!
|
||||||
|
targets = {}
|
||||||
|
|
||||||
|
vsvarsall = os.path.join( \
|
||||||
|
vc_path, \
|
||||||
|
'VC', \
|
||||||
|
'Auxiliary', \
|
||||||
|
'Build', \
|
||||||
|
'vcvarsall.bat')
|
||||||
|
|
||||||
|
# Modern Visual Studio versions, 2017 and up
|
||||||
|
if os.path.isfile(vsvarsall):
|
||||||
|
for target,realtarget in all_msvc_platforms[::-1]:
|
||||||
|
targets[target] = target_compiler( \
|
||||||
|
conf, \
|
||||||
|
'msvc', \
|
||||||
|
realtarget, \
|
||||||
|
version, \
|
||||||
|
target, \
|
||||||
|
vsvarsall)
|
||||||
|
# Visual Studio C++ Express versions?
|
||||||
|
elif os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
|
||||||
|
for target,realtarget in all_msvc_platforms[::-1]:
|
||||||
|
targets[target] = target_compiler( \
|
||||||
|
conf, \
|
||||||
|
'msvc', \
|
||||||
|
realtarget, \
|
||||||
|
version, \
|
||||||
|
target, \
|
||||||
|
os.path.join(vc_path, 'vcvarsall.bat'))
|
||||||
|
# Visual Studio 2010, up to 2015 (inclusive)
|
||||||
|
elif os.path.isfile( \
|
||||||
|
os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):
|
||||||
|
targets['x86'] = target_compiler( \
|
||||||
|
conf, \
|
||||||
|
'msvc', \
|
||||||
|
'x86', \
|
||||||
|
version, \
|
||||||
|
'x86', \
|
||||||
|
os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat'))
|
||||||
|
# Visual Studio 6, .NET 2002, .NET 2003
|
||||||
|
elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):
|
||||||
|
targets['x86'] = target_compiler( \
|
||||||
|
conf, \
|
||||||
|
'msvc', \
|
||||||
|
'x86', \
|
||||||
|
version, \
|
||||||
|
'', \
|
||||||
|
os.path.join(vc_path, 'Bin', 'vcvars32.bat'))
|
||||||
|
|
||||||
|
if targets:
|
||||||
|
versions['msvc %s' % 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 OSError:
|
||||||
|
msvc_version = Utils.winreg.OpenKey( \
|
||||||
|
Utils.winreg.HKEY_LOCAL_MACHINE, \
|
||||||
|
reg + "\\Setup\\Microsoft Visual C++")
|
||||||
|
|
||||||
|
path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir')
|
||||||
|
except OSError:
|
||||||
|
try:
|
||||||
|
msvc_version = Utils.winreg.OpenKey( \
|
||||||
|
Utils.winreg.HKEY_LOCAL_MACHINE, \
|
||||||
|
"SOFTWARE\\Wow6432node\\Microsoft\\VisualStudio\\SxS\\VS7")
|
||||||
|
|
||||||
|
path,type = Utils.winreg.QueryValueEx(msvc_version, version)
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
vc_paths.append((version, os.path.abspath(str(path))))
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
vc_paths.append((version, os.path.abspath(str(path))))
|
||||||
|
|
||||||
|
for version,vc_path in vc_paths:
|
||||||
|
conf.gather_msvc_targets(versions, version, vc_path)
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def gather_vswhere_versions(conf, versions):
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
except ImportError:
|
||||||
|
Logs.error('Visual Studio 2017 detection requires Python 2.6')
|
||||||
|
return
|
||||||
|
|
||||||
|
prg_path = os.environ.get( \
|
||||||
|
'ProgramFiles(x86)', \
|
||||||
|
os.environ.get('ProgramFiles', 'C:\\Program Files (x86)'))
|
||||||
|
|
||||||
|
vswhere = os.path.join( \
|
||||||
|
prg_path, \
|
||||||
|
'Microsoft Visual Studio', \
|
||||||
|
'Installer', \
|
||||||
|
'vswhere.exe')
|
||||||
|
|
||||||
|
args = [vswhere, '-products', '*', '-legacy', '-format', 'json']
|
||||||
|
try:
|
||||||
|
txt = conf.cmd_and_log(args)
|
||||||
|
except Errors.WafError as e:
|
||||||
|
Logs.debug('msvc: vswhere.exe failed %s', e)
|
||||||
|
return
|
||||||
|
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
txt = txt.decode(Utils.console_encoding())
|
||||||
|
|
||||||
|
arr = json.loads(txt)
|
||||||
|
arr.sort(key=lambda x: x['installationVersion'])
|
||||||
|
for entry in arr:
|
||||||
|
ver = entry['installationVersion']
|
||||||
|
ver = str('.'.join(ver.split('.')[:2]))
|
||||||
|
path = str(os.path.abspath(entry['installationPath']))
|
||||||
|
if os.path.exists(path) and ('msvc %s' % ver) not in versions:
|
||||||
|
conf.gather_msvc_targets(versions, ver, path)
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def get_msvc_versions(self, icl_func=None):
|
||||||
|
"""
|
||||||
|
:return: platform to compiler configurations
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
dct = icl_func(self) if icl_func else Utils.ordered_iter_dict()
|
||||||
|
self.gather_wsdk_versions(dct)
|
||||||
|
self.gather_msvc_versions(dct)
|
||||||
|
self.gather_vswhere_versions(dct)
|
||||||
|
Logs.debug('msvc: detected versions %r', list(dct.keys()))
|
||||||
|
return dct
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def setup_msvc(conf, versiondict):
|
||||||
|
"""
|
||||||
|
Checks installed compilers and targets and returns the first combination
|
||||||
|
from the user's options, env, or the global supported lists that checks.
|
||||||
|
|
||||||
|
:param versiondict: dict(platform -> dict(architecture -> configuration))
|
||||||
|
:type versiondict: dict(string -> dict(string -> target_compiler)
|
||||||
|
:return: the compiler, revision, path, include dirs, library paths and 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]
|
||||||
|
|
||||||
|
desired_versions = getattr(Options.options, 'msvc_version', '').split(',')
|
||||||
|
if desired_versions == ['']:
|
||||||
|
desired_versions = conf.env.MSVC_VERSIONS \
|
||||||
|
or list(reversed(sorted(versiondict.keys())))
|
||||||
|
|
||||||
|
# Override lazy detection by evaluating after the fact.
|
||||||
|
lazy_detect = getattr(Options.options, 'msvc_lazy', True)
|
||||||
|
if conf.env.MSVC_LAZY_AUTODETECT is False:
|
||||||
|
lazy_detect = False
|
||||||
|
|
||||||
|
if not lazy_detect:
|
||||||
|
for val in versiondict.values():
|
||||||
|
for arch in list(val.keys()):
|
||||||
|
cfg = val[arch]
|
||||||
|
cfg.evaluate()
|
||||||
|
if not cfg.is_valid:
|
||||||
|
del val[arch]
|
||||||
|
|
||||||
|
conf.env.MSVC_INSTALLED_VERSIONS = versiondict
|
||||||
|
|
||||||
|
for version in desired_versions:
|
||||||
|
Logs.debug('msvc: detecting %r - %r', version, desired_versions)
|
||||||
|
try:
|
||||||
|
targets = versiondict[version]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
for arch in platforms:
|
||||||
|
if arch in seen:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
seen.add(arch)
|
||||||
|
try:
|
||||||
|
cfg = targets[arch]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cfg.evaluate()
|
||||||
|
if cfg.is_valid:
|
||||||
|
compiler,revision = version.rsplit(' ', 1)
|
||||||
|
return compiler, \
|
||||||
|
revision, \
|
||||||
|
cfg.bindirs, \
|
||||||
|
cfg.incdirs, \
|
||||||
|
cfg.libdirs, \
|
||||||
|
cfg.cpu
|
||||||
|
|
||||||
|
conf.fatal( \
|
||||||
|
'msvc: Impossible to find a valid architecture for building %r - %r' \
|
||||||
|
% (desired_versions, list(versiondict.keys())))
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def detect_msvc(self, icl_func=None):
|
||||||
|
return self.setup_msvc(self.get_msvc_versions(icl_func))
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def autodetect(conf, arch=False, icl_func=None):
|
||||||
|
v = conf.env
|
||||||
|
if v.NO_MSVC_DETECT:
|
||||||
|
return
|
||||||
|
|
||||||
|
compiler, version, path, includes, libdirs, cpu = conf.detect_msvc(icl_func)
|
||||||
|
if arch:
|
||||||
|
v.DEST_CPU = cpu
|
||||||
|
|
||||||
|
v.PATH = path
|
||||||
|
v.INCLUDES = includes
|
||||||
|
v.LIBPATH = libdirs
|
||||||
|
v.MSVC_COMPILER = compiler
|
||||||
|
try:
|
||||||
|
v.MSVC_VERSION = float(version)
|
||||||
|
except ValueError:
|
||||||
|
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:
|
||||||
|
# assumes CL.exe
|
||||||
|
compiler_name = 'CL'
|
||||||
|
linker_name = 'LINK'
|
||||||
|
lib_name = 'LIB'
|
||||||
|
return compiler_name, linker_name, lib_name
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def find_msvc(conf):
|
||||||
|
"""Due to path format limitations, limit operation only to native Win32.
|
||||||
|
Yeah it sucks.
|
||||||
|
When using clang_cl, still call this, but unset v.CC and v.CXX.
|
||||||
|
"""
|
||||||
|
if sys.platform == 'cygwin':
|
||||||
|
conf.fatal('MSVC module does not work under cygwin Python!')
|
||||||
|
|
||||||
|
# the autodetection is supposed to be performed before entering in this method
|
||||||
|
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)
|
||||||
|
|
||||||
|
# compiler
|
||||||
|
cxx = conf.find_program(compiler_name, var='CXX', path_list=path)
|
||||||
|
|
||||||
|
# before setting anything, check if the compiler is really msvc
|
||||||
|
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')
|
||||||
|
|
||||||
|
# c/c++ compiler
|
||||||
|
v.CC = v.CXX = cxx
|
||||||
|
v.CC_NAME = v.CXX_NAME = 'msvc'
|
||||||
|
|
||||||
|
# linker
|
||||||
|
if not v.LINK_CXX:
|
||||||
|
conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX')
|
||||||
|
|
||||||
|
if not v.LINK_CC:
|
||||||
|
v.LINK_CC = v.LINK_CXX
|
||||||
|
|
||||||
|
# staticlib linker
|
||||||
|
if not v.AR:
|
||||||
|
stliblink = conf.find_program(lib_name, path_list=path, var='AR')
|
||||||
|
if not stliblink:
|
||||||
|
return
|
||||||
|
v.ARFLAGS = ['/nologo']
|
||||||
|
|
||||||
|
# manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
|
||||||
|
if v.MSVC_MANIFEST:
|
||||||
|
conf.find_program('MT', path_list=path, var='MT')
|
||||||
|
v.MTFLAGS = ['/nologo']
|
||||||
|
|
||||||
|
try:
|
||||||
|
conf.load('winres')
|
||||||
|
except Errors.ConfigurationError:
|
||||||
|
Logs.warn('Resource compiler not found. Compiling resource file is disabled')
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def msvc_common_flags(conf):
|
||||||
|
"""
|
||||||
|
Setup the flags required for executing the msvc compiler
|
||||||
|
"""
|
||||||
|
v = conf.env
|
||||||
|
|
||||||
|
v.DEST_BINFMT = 'pe'
|
||||||
|
v.append_value('CFLAGS', ['/nologo'])
|
||||||
|
v.append_value('CXXFLAGS', ['/nologo'])
|
||||||
|
v.append_value('LINKFLAGS', ['/nologo'])
|
||||||
|
v.DEFINES_ST = '/D%s'
|
||||||
|
|
||||||
|
v.CC_SRC_F = ''
|
||||||
|
v.CC_TGT_F = ['/c', '/Fo']
|
||||||
|
v.CXX_SRC_F = ''
|
||||||
|
v.CXX_TGT_F = ['/c', '/Fo']
|
||||||
|
|
||||||
|
if (v.MSVC_COMPILER == 'msvc' and v.MSVC_VERSION >= 8) \
|
||||||
|
or (v.MSVC_COMPILER == 'wsdk' and v.MSVC_VERSION >= 6):
|
||||||
|
v.CC_TGT_F = ['/FC'] + v.CC_TGT_F
|
||||||
|
v.CXX_TGT_F = ['/FC'] + v.CXX_TGT_F
|
||||||
|
|
||||||
|
v.CPPPATH_ST = '/I%s' # template for adding include paths
|
||||||
|
|
||||||
|
v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:'
|
||||||
|
|
||||||
|
# CRT specific flags
|
||||||
|
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'
|
||||||
|
|
||||||
|
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'
|
||||||
|
|
||||||
|
v.def_PATTERN = '/def:%s'
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def visual_studio_add_flags(self):
|
||||||
|
"""visual studio flags found in the system environment"""
|
||||||
|
v = self.env
|
||||||
|
if self.environ.get('INCLUDE'):
|
||||||
|
v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S'
|
||||||
|
if self.environ.get('LIB'):
|
||||||
|
v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x])
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def find_lt_names_msvc(self, libname, is_static=False):
|
||||||
|
"""
|
||||||
|
Win32/MSVC specific code to glean out information from libtool la files.
|
||||||
|
this function is not attached to the task_gen class. Returns a triplet:
|
||||||
|
(library absolute path, library name without extension, whether the library is static)
|
||||||
|
"""
|
||||||
|
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(r'\.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(r'\.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:
|
||||||
|
# file existence check has been made by find_lt_names
|
||||||
|
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)):
|
||||||
|
Logs.debug('msvc: lib found: %s', os.path.join(path,libn))
|
||||||
|
return re.sub(r'\.lib$', '',libn)
|
||||||
|
|
||||||
|
#if no lib can be found, just return the libname as msvc expects it
|
||||||
|
self.fatal('The library %r could not be found' % libname)
|
||||||
|
return re.sub(r'\.lib$', '', libname)
|
||||||
|
|
||||||
|
@conf
|
||||||
|
def check_lib_msvc(self, libname, is_static=False, uselib_store=None):
|
||||||
|
"""
|
||||||
|
Ideally we should be able to place the lib in the right env var, either STLIB or LIB,
|
||||||
|
but we don't distinguish static libs from shared libs.
|
||||||
|
This is ok since msvc doesn't have any special linker flag to select static libs (no env.STLIB_MARKER)
|
||||||
|
"""
|
||||||
|
libn = self.libname_msvc(libname, is_static)
|
||||||
|
|
||||||
|
if not uselib_store:
|
||||||
|
uselib_store = libname.upper()
|
||||||
|
|
||||||
|
if False and is_static: # disabled
|
||||||
|
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)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
########################### conf above, build below ###########################
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
@after_method('apply_link')
|
||||||
|
@feature('c', 'cxx')
|
||||||
|
def apply_flags_msvc(self):
|
||||||
|
"""
|
||||||
|
Add additional flags implied by msvc, such as subsystems and pdb files::
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
bld.stlib(source='main.c', target='bar', subsystem='gruik')
|
||||||
|
"""
|
||||||
|
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:] in ('debug', 'debug:full', 'debug:fastlink'):
|
||||||
|
pdbnode = self.link_task.outputs[0].change_ext('.pdb')
|
||||||
|
self.link_task.outputs.append(pdbnode)
|
||||||
|
|
||||||
|
if getattr(self, 'install_task', None):
|
||||||
|
self.pdb_install_task = self.add_install_files(
|
||||||
|
install_to=self.install_task.install_to, install_from=pdbnode)
|
||||||
|
break
|
||||||
|
|
||||||
|
@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib')
|
||||||
|
@after_method('apply_link')
|
||||||
|
def apply_manifest(self):
|
||||||
|
"""
|
||||||
|
Special linker for MSVC with support for embedding manifests into DLL's
|
||||||
|
and executables compiled by Visual Studio 2005 or probably later. Without
|
||||||
|
the manifest file, the binaries are unusable.
|
||||||
|
See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
|
||||||
|
"""
|
||||||
|
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.env.DO_MANIFEST = True
|
Loading…
Reference in New Issue