s3:smbd only initialize kernel oplocks if they are enabled for a share
[Samba/gebeck_regimport.git] / buildtools / wafadmin / Tools / msvc.py
blob4fde8b14687999cc6d49d232d4f99626408417f5
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Carlos Rafael Giani, 2006 (dv)
4 # Tamas Pal, 2007 (folti)
5 # Nicolas Mercier, 2009
6 # Microsoft Visual C++/Intel C++ compiler support - beta, needs more testing
8 # usage:
10 # conf.env['MSVC_VERSIONS'] = ['msvc 9.0', 'msvc 8.0', 'wsdk 7.0', 'intel 11', 'PocketPC 9.0', 'Smartphone 8.0']
11 # conf.env['MSVC_TARGETS'] = ['x64']
12 # conf.check_tool('msvc')
13 # OR conf.check_tool('msvc', funs='no_autodetect')
14 # conf.check_lib_msvc('gdi32')
15 # conf.check_libs_msvc('kernel32 user32', mandatory=true)
16 # ...
17 # obj.uselib = 'KERNEL32 USER32 GDI32'
19 # platforms and targets will be tested in the order they appear;
20 # the first good configuration will be used
21 # supported platforms :
22 # ia64, x64, x86, x86_amd64, x86_ia64
24 # compilers supported :
25 # msvc => Visual Studio, versions 7.1 (2003), 8,0 (2005), 9.0 (2008)
26 # wsdk => Windows SDK, versions 6.0, 6.1, 7.0
27 # icl => Intel compiler, versions 9,10,11
28 # Smartphone => Compiler/SDK for Smartphone devices (armv4/v4i)
29 # PocketPC => Compiler/SDK for PocketPC devices (armv4/v4i)
32 import os, sys, re, string, optparse
33 import Utils, TaskGen, Runner, Configure, Task, Options
34 from Logs import debug, info, warn, error
35 from TaskGen import after, before, feature
37 from Configure import conftest, conf
38 import ccroot, cc, cxx, ar, winres
39 from libtool import read_la_file
41 try:
42 import _winreg
43 except:
44 import winreg as _winreg
46 pproc = Utils.pproc
48 # importlibs provided by MSVC/Platform SDK. Do NOT search them....
49 g_msvc_systemlibs = """
50 aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
51 cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs
52 credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d
53 ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp
54 faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid
55 gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop
56 kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi
57 mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree
58 msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm
59 netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp
60 odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32
61 osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu
62 ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm
63 rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32
64 shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32
65 traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg
66 version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm
67 wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp
68 """.split()
71 all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'), ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64') ]
72 all_wince_platforms = [ ('armv4', 'arm'), ('armv4i', 'arm'), ('mipsii', 'mips'), ('mipsii_fp', 'mips'), ('mipsiv', 'mips'), ('mipsiv_fp', 'mips'), ('sh4', 'sh'), ('x86', 'cex86') ]
73 all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')]
75 def setup_msvc(conf, versions):
76 platforms = Utils.to_list(conf.env['MSVC_TARGETS']) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
77 desired_versions = conf.env['MSVC_VERSIONS'] or [v for v,_ in versions][::-1]
78 versiondict = dict(versions)
80 for version in desired_versions:
81 try:
82 targets = dict(versiondict [version])
83 for target in platforms:
84 try:
85 arch,(p1,p2,p3) = targets[target]
86 compiler,revision = version.split()
87 return compiler,revision,p1,p2,p3
88 except KeyError: continue
89 except KeyError: continue
90 conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)')
92 @conf
93 def get_msvc_version(conf, compiler, version, target, vcvars):
94 debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
95 batfile = os.path.join(conf.blddir, 'waf-print-msvc.bat')
96 f = open(batfile, 'w')
97 f.write("""@echo off
98 set INCLUDE=
99 set LIB=
100 call "%s" %s
101 echo PATH=%%PATH%%
102 echo INCLUDE=%%INCLUDE%%
103 echo LIB=%%LIB%%
104 """ % (vcvars,target))
105 f.close()
106 sout = Utils.cmd_output(['cmd', '/E:on', '/V:on', '/C', batfile])
107 lines = sout.splitlines()
109 for x in ('Setting environment', 'Setting SDK environment', 'Intel(R) C++ Compiler'):
110 if lines[0].find(x) != -1:
111 break
112 else:
113 debug('msvc: get_msvc_version: %r %r %r -> not found', compiler, version, target)
114 conf.fatal('msvc: Impossible to find a valid architecture for building (in get_msvc_version)')
116 for line in lines[1:]:
117 if line.startswith('PATH='):
118 path = line[5:]
119 MSVC_PATH = path.split(';')
120 elif line.startswith('INCLUDE='):
121 MSVC_INCDIR = [i for i in line[8:].split(';') if i]
122 elif line.startswith('LIB='):
123 MSVC_LIBDIR = [i for i in line[4:].split(';') if i]
125 # Check if the compiler is usable at all.
126 # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.
127 env = {}
128 env.update(os.environ)
129 env.update(PATH = path)
130 compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
131 cxx = conf.find_program(compiler_name, path_list=MSVC_PATH)
132 # delete CL if exists. because it could contain parameters wich can change cl's behaviour rather catastrophically.
133 if env.has_key('CL'):
134 del(env['CL'])
136 try:
137 p = pproc.Popen([cxx, '/help'], env=env, stdout=pproc.PIPE, stderr=pproc.PIPE)
138 out, err = p.communicate()
139 if p.returncode != 0:
140 raise Exception('return code: %r: %r' % (p.returncode, err))
141 except Exception, e:
142 debug('msvc: get_msvc_version: %r %r %r -> failure', compiler, version, target)
143 debug(str(e))
144 conf.fatal('msvc: cannot run the compiler (in get_msvc_version)')
145 else:
146 debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
148 return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)
150 @conf
151 def gather_wsdk_versions(conf, versions):
152 version_pattern = re.compile('^v..?.?\...?.?')
153 try:
154 all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
155 except WindowsError:
156 try:
157 all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
158 except WindowsError:
159 return
160 index = 0
161 while 1:
162 try:
163 version = _winreg.EnumKey(all_versions, index)
164 except WindowsError:
165 break
166 index = index + 1
167 if not version_pattern.match(version):
168 continue
169 try:
170 msvc_version = _winreg.OpenKey(all_versions, version)
171 path,type = _winreg.QueryValueEx(msvc_version,'InstallationFolder')
172 except WindowsError:
173 continue
174 if os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
175 targets = []
176 for target,arch in all_msvc_platforms:
177 try:
178 targets.append((target, (arch, conf.get_msvc_version('wsdk', version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')))))
179 except Configure.ConfigurationError:
180 pass
181 versions.append(('wsdk ' + version[1:], targets))
183 @conf
184 def gather_msvc_versions(conf, versions):
185 # checks SmartPhones SDKs
186 try:
187 ce_sdk = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')
188 except WindowsError:
189 try:
190 ce_sdk = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')
191 except WindowsError:
192 ce_sdk = ''
193 if ce_sdk:
194 supported_wince_platforms = []
195 ce_index = 0
196 while 1:
197 try:
198 sdk_device = _winreg.EnumKey(ce_sdk, ce_index)
199 except WindowsError:
200 break
201 ce_index = ce_index + 1
202 sdk = _winreg.OpenKey(ce_sdk, sdk_device)
203 path,type = _winreg.QueryValueEx(sdk, 'SDKRootDir')
204 path=str(path)
205 path,device = os.path.split(path)
206 if not device:
207 path,device = os.path.split(path)
208 for arch,compiler in all_wince_platforms:
209 platforms = []
210 if os.path.isdir(os.path.join(path, device, 'Lib', arch)):
211 platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch)))
212 if platforms:
213 supported_wince_platforms.append((device, platforms))
214 # checks MSVC
215 version_pattern = re.compile('^..?\...?')
216 for vcver,vcvar in [('VCExpress','exp'), ('VisualStudio','')]:
217 try:
218 all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\'+vcver)
219 except WindowsError:
220 try:
221 all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\'+vcver)
222 except WindowsError:
223 continue
224 index = 0
225 while 1:
226 try:
227 version = _winreg.EnumKey(all_versions, index)
228 except WindowsError:
229 break
230 index = index + 1
231 if not version_pattern.match(version):
232 continue
233 try:
234 msvc_version = _winreg.OpenKey(all_versions, version + "\\Setup\\VS")
235 path,type = _winreg.QueryValueEx(msvc_version, 'ProductDir')
236 path=str(path)
237 targets = []
238 if ce_sdk:
239 for device,platforms in supported_wince_platforms:
240 cetargets = []
241 for platform,compiler,include,lib in platforms:
242 winCEpath = os.path.join(path, 'VC', 'ce')
243 if os.path.isdir(winCEpath):
244 common_bindirs,_1,_2 = conf.get_msvc_version('msvc', version, 'x86', os.path.join(path, 'Common7', 'Tools', 'vsvars32.bat'))
245 if os.path.isdir(os.path.join(winCEpath, 'lib', platform)):
246 bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)] + common_bindirs
247 incdirs = [include, os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include')]
248 libdirs = [lib, os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform)]
249 cetargets.append((platform, (platform, (bindirs,incdirs,libdirs))))
250 versions.append((device+' '+version, cetargets))
251 if os.path.isfile(os.path.join(path, 'VC', 'vcvarsall.bat')):
252 for target,realtarget in all_msvc_platforms[::-1]:
253 try:
254 targets.append((target, (realtarget, conf.get_msvc_version('msvc', version, target, os.path.join(path, 'VC', 'vcvarsall.bat')))))
255 except:
256 pass
257 elif os.path.isfile(os.path.join(path, 'Common7', 'Tools', 'vsvars32.bat')):
258 try:
259 targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, 'x86', os.path.join(path, 'Common7', 'Tools', 'vsvars32.bat')))))
260 except Configure.ConfigurationError:
261 pass
262 versions.append(('msvc '+version, targets))
264 except WindowsError:
265 continue
267 @conf
268 def gather_icl_versions(conf, versions):
269 version_pattern = re.compile('^...?.?\....?.?')
270 try:
271 all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')
272 except WindowsError:
273 try:
274 all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++')
275 except WindowsError:
276 return
277 index = 0
278 while 1:
279 try:
280 version = _winreg.EnumKey(all_versions, index)
281 except WindowsError:
282 break
283 index = index + 1
284 if not version_pattern.match(version):
285 continue
286 targets = []
287 for target,arch in all_icl_platforms:
288 try:
289 icl_version = _winreg.OpenKey(all_versions, version+'\\'+target)
290 path,type = _winreg.QueryValueEx(icl_version,'ProductDir')
291 if os.path.isfile(os.path.join(path, 'bin', 'iclvars.bat')):
292 try:
293 targets.append((target, (arch, conf.get_msvc_version('intel', version, target, os.path.join(path, 'bin', 'iclvars.bat')))))
294 except Configure.ConfigurationError:
295 pass
296 except WindowsError:
297 continue
298 major = version[0:2]
299 versions.append(('intel ' + major, targets))
301 @conf
302 def get_msvc_versions(conf):
303 if not conf.env.MSVC_INSTALLED_VERSIONS:
304 lst = []
305 conf.gather_msvc_versions(lst)
306 conf.gather_wsdk_versions(lst)
307 conf.gather_icl_versions(lst)
308 conf.env.MSVC_INSTALLED_VERSIONS = lst
309 return conf.env.MSVC_INSTALLED_VERSIONS
311 @conf
312 def print_all_msvc_detected(conf):
313 for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']:
314 info(version)
315 for target,l in targets:
316 info("\t"+target)
318 def detect_msvc(conf):
319 versions = get_msvc_versions(conf)
320 return setup_msvc(conf, versions)
322 @conf
323 def find_lt_names_msvc(self, libname, is_static=False):
325 Win32/MSVC specific code to glean out information from libtool la files.
326 this function is not attached to the task_gen class
328 lt_names=[
329 'lib%s.la' % libname,
330 '%s.la' % libname,
333 for path in self.env['LIBPATH']:
334 for la in lt_names:
335 laf=os.path.join(path,la)
336 dll=None
337 if os.path.exists(laf):
338 ltdict=read_la_file(laf)
339 lt_libdir=None
340 if ltdict.get('libdir', ''):
341 lt_libdir = ltdict['libdir']
342 if not is_static and ltdict.get('library_names', ''):
343 dllnames=ltdict['library_names'].split()
344 dll=dllnames[0].lower()
345 dll=re.sub('\.dll$', '', dll)
346 return (lt_libdir, dll, False)
347 elif ltdict.get('old_library', ''):
348 olib=ltdict['old_library']
349 if os.path.exists(os.path.join(path,olib)):
350 return (path, olib, True)
351 elif lt_libdir != '' and os.path.exists(os.path.join(lt_libdir,olib)):
352 return (lt_libdir, olib, True)
353 else:
354 return (None, olib, True)
355 else:
356 raise Utils.WafError('invalid libtool object file: %s' % laf)
357 return (None, None, None)
359 @conf
360 def libname_msvc(self, libname, is_static=False, mandatory=False):
361 lib = libname.lower()
362 lib = re.sub('\.lib$','',lib)
364 if lib in g_msvc_systemlibs:
365 return lib
367 lib=re.sub('^lib','',lib)
369 if lib == 'm':
370 return None
372 (lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static)
374 if lt_path != None and lt_libname != None:
375 if lt_static == True:
376 # file existance check has been made by find_lt_names
377 return os.path.join(lt_path,lt_libname)
379 if lt_path != None:
380 _libpaths=[lt_path] + self.env['LIBPATH']
381 else:
382 _libpaths=self.env['LIBPATH']
384 static_libs=[
385 'lib%ss.lib' % lib,
386 'lib%s.lib' % lib,
387 '%ss.lib' % lib,
388 '%s.lib' %lib,
391 dynamic_libs=[
392 'lib%s.dll.lib' % lib,
393 'lib%s.dll.a' % lib,
394 '%s.dll.lib' % lib,
395 '%s.dll.a' % lib,
396 'lib%s_d.lib' % lib,
397 '%s_d.lib' % lib,
398 '%s.lib' %lib,
401 libnames=static_libs
402 if not is_static:
403 libnames=dynamic_libs + static_libs
405 for path in _libpaths:
406 for libn in libnames:
407 if os.path.exists(os.path.join(path, libn)):
408 debug('msvc: lib found: %s', os.path.join(path,libn))
409 return re.sub('\.lib$', '',libn)
411 #if no lib can be found, just return the libname as msvc expects it
412 if mandatory:
413 self.fatal("The library %r could not be found" % libname)
414 return re.sub('\.lib$', '', libname)
416 @conf
417 def check_lib_msvc(self, libname, is_static=False, uselib_store=None, mandatory=False):
418 "This is the api to use"
419 libn = self.libname_msvc(libname, is_static, mandatory)
421 if not uselib_store:
422 uselib_store = libname.upper()
424 # Note: ideally we should be able to place the lib in the right env var, either STATICLIB or LIB,
425 # but we don't distinguish static libs from shared libs.
426 # This is ok since msvc doesn't have any special linker flag to select static libs (no env['STATICLIB_MARKER'])
427 if False and is_static: # disabled
428 self.env['STATICLIB_' + uselib_store] = [libn]
429 else:
430 self.env['LIB_' + uselib_store] = [libn]
432 @conf
433 def check_libs_msvc(self, libnames, is_static=False, mandatory=False):
434 for libname in Utils.to_list(libnames):
435 self.check_lib_msvc(libname, is_static, mandatory=mandatory)
437 @conftest
438 def no_autodetect(conf):
439 conf.eval_rules(detect.replace('autodetect', ''))
442 detect = '''
443 autodetect
444 find_msvc
445 msvc_common_flags
446 cc_load_tools
447 cxx_load_tools
448 cc_add_flags
449 cxx_add_flags
450 link_add_flags
453 @conftest
454 def autodetect(conf):
455 v = conf.env
456 compiler, version, path, includes, libdirs = detect_msvc(conf)
457 v['PATH'] = path
458 v['CPPPATH'] = includes
459 v['LIBPATH'] = libdirs
460 v['MSVC_COMPILER'] = compiler
462 def _get_prog_names(conf, compiler):
463 if compiler=='intel':
464 compiler_name = 'ICL'
465 linker_name = 'XILINK'
466 lib_name = 'XILIB'
467 else:
468 # assumes CL.exe
469 compiler_name = 'CL'
470 linker_name = 'LINK'
471 lib_name = 'LIB'
472 return compiler_name, linker_name, lib_name
474 @conftest
475 def find_msvc(conf):
476 # due to path format limitations, limit operation only to native Win32. Yeah it sucks.
477 if sys.platform != 'win32':
478 conf.fatal('MSVC module only works under native Win32 Python! cygwin is not supported yet')
480 v = conf.env
482 compiler, version, path, includes, libdirs = detect_msvc(conf)
484 compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
485 has_msvc_manifest = (compiler == 'msvc' and float(version) >= 8) or (compiler == 'wsdk' and float(version) >= 6) or (compiler == 'intel' and float(version) >= 11)
487 # compiler
488 cxx = None
489 if v.CXX: cxx = v.CXX
490 elif 'CXX' in conf.environ: cxx = conf.environ['CXX']
491 if not cxx: cxx = conf.find_program(compiler_name, var='CXX', path_list=path, mandatory=True)
492 cxx = conf.cmd_to_list(cxx)
494 # before setting anything, check if the compiler is really msvc
495 env = dict(conf.environ)
496 env.update(PATH = ';'.join(path))
497 if not Utils.cmd_output([cxx, '/nologo', '/?'], silent=True, env=env):
498 conf.fatal('the msvc compiler could not be identified')
500 link = v.LINK_CXX
501 if not link:
502 link = conf.find_program(linker_name, path_list=path, mandatory=True)
503 ar = v.AR
504 if not ar:
505 ar = conf.find_program(lib_name, path_list=path, mandatory=True)
507 # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
508 mt = v.MT
509 if has_msvc_manifest:
510 mt = conf.find_program('MT', path_list=path, mandatory=True)
512 # no more possibility of failure means the data state will be consistent
513 # we may store the data safely now
515 v.MSVC_MANIFEST = has_msvc_manifest
516 v.PATH = path
517 v.CPPPATH = includes
518 v.LIBPATH = libdirs
520 # c/c++ compiler
521 v.CC = v.CXX = cxx
522 v.CC_NAME = v.CXX_NAME = 'msvc'
524 v.LINK = v.LINK_CXX = link
525 if not v.LINK_CC:
526 v.LINK_CC = v.LINK_CXX
528 v.AR = ar
529 v.MT = mt
530 v.MTFLAGS = v.ARFLAGS = ['/NOLOGO']
533 conf.check_tool('winres')
535 if not conf.env.WINRC:
536 warn('Resource compiler not found. Compiling resource file is disabled')
538 # environment flags
539 try: v.prepend_value('CPPPATH', conf.environ['INCLUDE'])
540 except KeyError: pass
541 try: v.prepend_value('LIBPATH', conf.environ['LIB'])
542 except KeyError: pass
544 @conftest
545 def msvc_common_flags(conf):
546 v = conf.env
548 v['CPPFLAGS'] = ['/W3', '/nologo']
550 v['CCDEFINES_ST'] = '/D%s'
551 v['CXXDEFINES_ST'] = '/D%s'
553 # TODO just use _WIN32, which defined by the compiler itself!
554 v['CCDEFINES'] = ['WIN32'] # avoid using this, any compiler predefines the _WIN32 marcro anyway
555 v['CXXDEFINES'] = ['WIN32'] # avoid using this, any compiler predefines the _WIN32 marcro anyway
557 v['_CCINCFLAGS'] = []
558 v['_CCDEFFLAGS'] = []
559 v['_CXXINCFLAGS'] = []
560 v['_CXXDEFFLAGS'] = []
562 v['CC_SRC_F'] = ''
563 v['CC_TGT_F'] = ['/c', '/Fo']
564 v['CXX_SRC_F'] = ''
565 v['CXX_TGT_F'] = ['/c', '/Fo']
567 v['CPPPATH_ST'] = '/I%s' # template for adding include paths
569 v['AR_TGT_F'] = v['CCLNK_TGT_F'] = v['CXXLNK_TGT_F'] = '/OUT:'
571 # Subsystem specific flags
572 v['CPPFLAGS_CONSOLE'] = ['/SUBSYSTEM:CONSOLE']
573 v['CPPFLAGS_NATIVE'] = ['/SUBSYSTEM:NATIVE']
574 v['CPPFLAGS_POSIX'] = ['/SUBSYSTEM:POSIX']
575 v['CPPFLAGS_WINDOWS'] = ['/SUBSYSTEM:WINDOWS']
576 v['CPPFLAGS_WINDOWSCE'] = ['/SUBSYSTEM:WINDOWSCE']
578 # CRT specific flags
579 v['CPPFLAGS_CRT_MULTITHREADED'] = ['/MT']
580 v['CPPFLAGS_CRT_MULTITHREADED_DLL'] = ['/MD']
582 # TODO these are defined by the compiler itself!
583 v['CPPDEFINES_CRT_MULTITHREADED'] = ['_MT'] # this is defined by the compiler itself!
584 v['CPPDEFINES_CRT_MULTITHREADED_DLL'] = ['_MT', '_DLL'] # these are defined by the compiler itself!
586 v['CPPFLAGS_CRT_MULTITHREADED_DBG'] = ['/MTd']
587 v['CPPFLAGS_CRT_MULTITHREADED_DLL_DBG'] = ['/MDd']
589 # TODO these are defined by the compiler itself!
590 v['CPPDEFINES_CRT_MULTITHREADED_DBG'] = ['_DEBUG', '_MT'] # these are defined by the compiler itself!
591 v['CPPDEFINES_CRT_MULTITHREADED_DLL_DBG'] = ['_DEBUG', '_MT', '_DLL'] # these are defined by the compiler itself!
593 # compiler debug levels
594 v['CCFLAGS'] = ['/TC']
595 v['CCFLAGS_OPTIMIZED'] = ['/O2', '/DNDEBUG']
596 v['CCFLAGS_RELEASE'] = ['/O2', '/DNDEBUG']
597 v['CCFLAGS_DEBUG'] = ['/Od', '/RTC1', '/ZI']
598 v['CCFLAGS_ULTRADEBUG'] = ['/Od', '/RTC1', '/ZI']
600 v['CXXFLAGS'] = ['/TP', '/EHsc']
601 v['CXXFLAGS_OPTIMIZED'] = ['/O2', '/DNDEBUG']
602 v['CXXFLAGS_RELEASE'] = ['/O2', '/DNDEBUG']
604 v['CXXFLAGS_DEBUG'] = ['/Od', '/RTC1', '/ZI']
605 v['CXXFLAGS_ULTRADEBUG'] = ['/Od', '/RTC1', '/ZI']
607 # linker
608 v['LIB'] = []
610 v['LIB_ST'] = '%s.lib' # template for adding libs
611 v['LIBPATH_ST'] = '/LIBPATH:%s' # template for adding libpaths
612 v['STATICLIB_ST'] = 'lib%s.lib' # Note: to be able to distinguish between a static lib and a dll import lib, it's a good pratice to name the static lib 'lib%s.lib' and the dll import lib '%s.lib'
613 v['STATICLIBPATH_ST'] = '/LIBPATH:%s'
615 v['LINKFLAGS'] = ['/NOLOGO']
616 if v['MSVC_MANIFEST']:
617 v.append_value('LINKFLAGS', '/MANIFEST')
618 v['LINKFLAGS_DEBUG'] = ['/DEBUG']
619 v['LINKFLAGS_ULTRADEBUG'] = ['/DEBUG']
621 # shared library
622 v['shlib_CCFLAGS'] = ['']
623 v['shlib_CXXFLAGS'] = ['']
624 v['shlib_LINKFLAGS']= ['/DLL']
625 v['shlib_PATTERN'] = '%s.dll'
626 v['implib_PATTERN'] = '%s.lib'
627 v['IMPLIB_ST'] = '/IMPLIB:%s'
629 # static library
630 v['staticlib_LINKFLAGS'] = ['']
631 v['staticlib_PATTERN'] = 'lib%s.lib' # Note: to be able to distinguish between a static lib and a dll import lib, it's a good pratice to name the static lib 'lib%s.lib' and the dll import lib '%s.lib'
633 # program
634 v['program_PATTERN'] = '%s.exe'
637 #######################################################################################################
638 ##### conf above, build below
640 @after('apply_link')
641 @feature('cc', 'cxx')
642 def apply_flags_msvc(self):
643 if self.env.CC_NAME != 'msvc' or not self.link_task:
644 return
646 subsystem = getattr(self, 'subsystem', '')
647 if subsystem:
648 subsystem = '/subsystem:%s' % subsystem
649 flags = 'cstaticlib' in self.features and 'ARFLAGS' or 'LINKFLAGS'
650 self.env.append_value(flags, subsystem)
652 if getattr(self, 'link_task', None) and not 'cstaticlib' in self.features:
653 for f in self.env.LINKFLAGS:
654 d = f.lower()
655 if d[1:] == 'debug':
656 pdbnode = self.link_task.outputs[0].change_ext('.pdb')
657 pdbfile = pdbnode.bldpath(self.env)
658 self.link_task.outputs.append(pdbnode)
659 self.bld.install_files(self.install_path, [pdbnode], env=self.env)
660 break
662 @feature('cprogram', 'cshlib', 'cstaticlib')
663 @after('apply_lib_vars')
664 @before('apply_obj_vars')
665 def apply_obj_vars_msvc(self):
666 if self.env['CC_NAME'] != 'msvc':
667 return
669 try:
670 self.meths.remove('apply_obj_vars')
671 except ValueError:
672 pass
674 libpaths = getattr(self, 'libpaths', [])
675 if not libpaths: self.libpaths = libpaths
677 env = self.env
678 app = env.append_unique
680 cpppath_st = env['CPPPATH_ST']
681 lib_st = env['LIB_ST']
682 staticlib_st = env['STATICLIB_ST']
683 libpath_st = env['LIBPATH_ST']
684 staticlibpath_st = env['STATICLIBPATH_ST']
686 for i in env['LIBPATH']:
687 app('LINKFLAGS', libpath_st % i)
688 if not libpaths.count(i):
689 libpaths.append(i)
691 for i in env['LIBPATH']:
692 app('LINKFLAGS', staticlibpath_st % i)
693 if not libpaths.count(i):
694 libpaths.append(i)
696 # i doubt that anyone will make a fully static binary anyway
697 if not env['FULLSTATIC']:
698 if env['STATICLIB'] or env['LIB']:
699 app('LINKFLAGS', env['SHLIB_MARKER']) # TODO does SHLIB_MARKER work?
701 for i in env['STATICLIB']:
702 app('LINKFLAGS', staticlib_st % i)
704 for i in env['LIB']:
705 app('LINKFLAGS', lib_st % i)
707 # split the manifest file processing from the link task, like for the rc processing
709 @feature('cprogram', 'cshlib')
710 @after('apply_link')
711 def apply_manifest(self):
712 """Special linker for MSVC with support for embedding manifests into DLL's
713 and executables compiled by Visual Studio 2005 or probably later. Without
714 the manifest file, the binaries are unusable.
715 See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx"""
717 if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST:
718 out_node = self.link_task.outputs[0]
719 man_node = out_node.parent.find_or_declare(out_node.name + '.manifest')
720 self.link_task.outputs.append(man_node)
721 self.link_task.do_manifest = True
723 def exec_mf(self):
724 env = self.env
725 mtool = env['MT']
726 if not mtool:
727 return 0
729 self.do_manifest = False
731 outfile = self.outputs[0].bldpath(env)
733 manifest = None
734 for out_node in self.outputs:
735 if out_node.name.endswith('.manifest'):
736 manifest = out_node.bldpath(env)
737 break
738 if manifest is None:
739 # Should never get here. If we do, it means the manifest file was
740 # never added to the outputs list, thus we don't have a manifest file
741 # to embed, so we just return.
742 return 0
744 # embedding mode. Different for EXE's and DLL's.
745 # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx
746 mode = ''
747 if 'cprogram' in self.generator.features:
748 mode = '1'
749 elif 'cshlib' in self.generator.features:
750 mode = '2'
752 debug('msvc: embedding manifest')
753 #flags = ' '.join(env['MTFLAGS'] or [])
755 lst = []
756 lst.extend([env['MT']])
757 lst.extend(Utils.to_list(env['MTFLAGS']))
758 lst.extend(Utils.to_list("-manifest"))
759 lst.extend(Utils.to_list(manifest))
760 lst.extend(Utils.to_list("-outputresource:%s;%s" % (outfile, mode)))
762 #cmd='%s %s -manifest "%s" -outputresource:"%s";#%s' % (mtool, flags,
763 # manifest, outfile, mode)
764 lst = [lst]
765 return self.exec_command(*lst)
767 ########## stupid evil command modification: concatenate the tokens /Fx, /doc, and /x: with the next token
769 def exec_command_msvc(self, *k, **kw):
770 "instead of quoting all the paths and keep using the shell, we can just join the options msvc is interested in"
771 if self.env['CC_NAME'] == 'msvc':
772 if isinstance(k[0], list):
773 lst = []
774 carry = ''
775 for a in k[0]:
776 if len(a) == 3 and a.startswith('/F') or a == '/doc' or a[-1] == ':':
777 carry = a
778 else:
779 lst.append(carry + a)
780 carry = ''
781 k = [lst]
783 env = dict(os.environ)
784 env.update(PATH = ';'.join(self.env['PATH']))
785 kw['env'] = env
787 ret = self.generator.bld.exec_command(*k, **kw)
788 if ret: return ret
789 if getattr(self, 'do_manifest', None):
790 ret = exec_mf(self)
791 return ret
793 for k in 'cc cxx winrc cc_link cxx_link static_link qxx'.split():
794 cls = Task.TaskBase.classes.get(k, None)
795 if cls:
796 cls.exec_command = exec_command_msvc