]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/msvc.py
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / build / src / tools / msvc.py
1 # Copyright (c) 2003 David Abrahams.
2 # Copyright (c) 2005 Vladimir Prus.
3 # Copyright (c) 2005 Alexey Pakhunov.
4 # Copyright (c) 2006 Bojan Resnik.
5 # Copyright (c) 2006 Ilya Sokolov.
6 # Copyright (c) 2007 Rene Rivera
7 # Copyright (c) 2008 Jurko Gospodnetic
8 # Copyright (c) 2011 Juraj Ivancic
9 #
10 # Use, modification and distribution is subject to the Boost Software
11 # License Version 1.0. (See accompanying file LICENSE_1_0.txt or
12 # http://www.boost.org/LICENSE_1_0.txt)
13
14 ################################################################################
15 #
16 # MSVC Boost Build toolset module.
17 # --------------------------------
18 #
19 # All toolset versions need to have their location either auto-detected or
20 # explicitly specified except for the special 'default' version that expects the
21 # environment to find the needed tools or report an error.
22 #
23 ################################################################################
24
25 from os import environ
26 import os.path
27 import re
28 import _winreg
29
30 import bjam
31
32 from b2.tools import common, rc, pch, builtin, mc, midl
33 from b2.build import feature, type, toolset, generators, property_set
34 from b2.build.property import Property
35 from b2.util import path
36 from b2.manager import get_manager
37 from b2.build.generators import Generator
38 from b2.build.toolset import flags
39 from b2.util.utility import to_seq, on_windows
40 from b2.tools.common import Configurations
41
42 __debug = None
43
44 def debug():
45 global __debug
46 if __debug is None:
47 __debug = "--debug-configuration" in bjam.variable("ARGV")
48 return __debug
49
50
51 # It is not yet clear what to do with Cygwin on python port.
52 def on_cygwin():
53 return False
54
55
56 type.register('MANIFEST', ['manifest'])
57 feature.feature('embed-manifest',['on','off'], ['incidental', 'propagated']) ;
58
59 type.register('PDB',['pdb'])
60
61 ################################################################################
62 #
63 # Public rules.
64 #
65 ################################################################################
66
67 # Initialize a specific toolset version configuration. As the result, path to
68 # compiler and, possible, program names are set up, and will be used when that
69 # version of compiler is requested. For example, you might have:
70 #
71 # using msvc : 6.5 : cl.exe ;
72 # using msvc : 7.0 : Y:/foo/bar/cl.exe ;
73 #
74 # The version parameter may be omitted:
75 #
76 # using msvc : : Z:/foo/bar/cl.exe ;
77 #
78 # The following keywords have special meanings when specified as versions:
79 # - all - all detected but not yet used versions will be marked as used
80 # with their default options.
81 # - default - this is an equivalent to an empty version.
82 #
83 # Depending on a supplied version, detected configurations and presence 'cl.exe'
84 # in the path different results may be achieved. The following table describes
85 # the possible scenarios:
86 #
87 # Nothing "x.y"
88 # Passed Nothing "x.y" detected, detected,
89 # version detected detected cl.exe in path cl.exe in path
90 #
91 # default Error Use "x.y" Create "default" Use "x.y"
92 # all None Use all None Use all
93 # x.y - Use "x.y" - Use "x.y"
94 # a.b Error Error Create "a.b" Create "a.b"
95 #
96 # "x.y" - refers to a detected version;
97 # "a.b" - refers to an undetected version.
98 #
99 # FIXME: Currently the command parameter and the <compiler> property parameter
100 # seem to overlap in duties. Remove this duplication. This seems to be related
101 # to why someone started preparing to replace init with configure rules.
102
103 def init(version = None, command = None, options = None):
104 # When initialized from
105 # using msvc : x.0 ;
106 # we get version as a single element list i.e. ['x.0'],
107 # but when specified from the command line we get a string i.e. 'x.0'.
108 # We want to work with a string, so unpack the list if needed.
109 is_single_element_list = (isinstance(version,list) and len(version) == 1)
110 assert(version==None or isinstance(version,str) or is_single_element_list)
111 if is_single_element_list:
112 version = version[0]
113
114 options = to_seq(options)
115 command = to_seq(command)
116
117 if command:
118 options.extend("<command>"+cmd for cmd in command)
119 configure(version,options)
120
121 def configure(version=None, options=None):
122 if version == "all":
123 if options:
124 raise RuntimeError("MSVC toolset configuration: options should be empty when '{}' is specified.".format(version))
125
126 # Configure (i.e. mark as used) all registered versions.
127 all_versions = __versions.all()
128 if not all_versions:
129 if debug():
130 print "notice: [msvc-cfg] Asked to configure all registered" \
131 "msvc toolset versions when there are none currently" \
132 "registered." ;
133 else:
134 for v in all_versions:
135 # Note that there is no need to skip already configured
136 # versions here as this will request configure-really rule
137 # to configure the version using default options which will
138 # in turn cause it to simply do nothing in case the version
139 # has already been configured.
140 configure_really(v)
141 elif version == "default":
142 configure_really(None,options)
143 else:
144 configure_really(version, options)
145
146 def extend_conditions(conditions,exts):
147 return [ cond + '/' + ext for cond in conditions for ext in exts ]
148
149 def configure_version_specific(toolset_arg, version, conditions):
150 # Starting with versions 7.0, the msvc compiler have the /Zc:forScope and
151 # /Zc:wchar_t options that improve C++ standard conformance, but those
152 # options are off by default. If we are sure that the msvc version is at
153 # 7.*, add those options explicitly. We can be sure either if user specified
154 # version 7.* explicitly or if we auto-detected the version ourselves.
155 if not re.search('^6\\.', version):
156 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',conditions, ['/Zc:forScope','/Zc:wchar_t'])
157 toolset.flags('{}.compile.c++'.format(toolset_arg), 'C++FLAGS',conditions, ['/wd4675'])
158
159 # Explicitly disable the 'function is deprecated' warning. Some msvc
160 # versions have a bug, causing them to emit the deprecation warning even
161 # with /W0.
162 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>off']), ['/wd4996'])
163 if re.search('^[78]\.', version):
164 # 64-bit compatibility warning deprecated since 9.0, see
165 # http://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx
166 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>all']), ['/Wp64'])
167
168 #
169 # Processor-specific optimization.
170 #
171 if re.search('^[67]', version ):
172 # 8.0 deprecates some of the options.
173 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed','<optimization>space']), ['/Ogiy', '/Gs'])
174 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed']), ['/Ot'])
175 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>space']), ['/Os'])
176
177 cpu_arch_i386_cond = extend_conditions(conditions, __cpu_arch_i386)
178 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>']),['/GB'])
179 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>i486']),['/G4'])
180
181 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g5]), ['/G5'])
182 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g6]), ['/G6'])
183 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g7]), ['/G7'])
184
185 # Improve floating-point accuracy. Otherwise, some of C++ Boost's "math"
186 # tests will fail.
187 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', conditions, ['/Op'])
188
189 # 7.1 and below have single-threaded static RTL.
190 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>off/<runtime-link>static/<threading>single']), ['/ML'])
191 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>on/<runtime-link>static/<threading>single']), ['/MLd'])
192 else:
193 # 8.0 and above adds some more options.
194 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' for a in __cpu_arch_amd64]), ['/favor:blend'])
195
196 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' + t for a in __cpu_arch_amd64 for t in __cpu_type_em64t]), ['/favor:EM64T'])
197 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' + t for a in __cpu_arch_amd64 for t in __cpu_type_amd64]), ['/favor:AMD64'])
198
199 # 8.0 and above only has multi-threaded static RTL.
200 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>off/<runtime-link>static/<threading>single']), ['/MT'])
201 toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>on/<runtime-link>static/<threading>single']), ['/MTd'])
202
203 # Specify target machine type so the linker will not need to guess.
204 toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_amd64), ['/MACHINE:X64'])
205 toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_i386), ['/MACHINE:X86'])
206 toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_ia64), ['/MACHINE:IA64'])
207
208 # Make sure that manifest will be generated even if there is no
209 # dependencies to put there.
210 toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', conditions, ['/MANIFEST'])
211
212
213 # Registers this toolset including all of its flags, features & generators. Does
214 # nothing on repeated calls.
215
216 def register_toolset():
217 if not 'msvc' in feature.values('toolset'):
218 register_toolset_really()
219
220
221 engine = get_manager().engine()
222
223 # this rule sets up the pdb file that will be used when generating static
224 # libraries and the debug-store option is database, so that the compiler
225 # puts all debug info into a single .pdb file named after the library
226 #
227 # Poking at source targets this way is probably not clean, but it's the
228 # easiest approach.
229 def archive(targets, sources=None, properties=None):
230 bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb')
231
232 # Declare action for creating static libraries. If library exists, remove it
233 # before adding files. See
234 # http://article.gmane.org/gmane.comp.lib.boost.build/4241 for rationale.
235 if not on_cygwin():
236 engine.register_action(
237 'msvc.archive',
238 '''if exist "$(<[1])" DEL "$(<[1])"
239 $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=
240 "$(>)"
241 $(LIBRARIES_MENTIONED_BY_FILE)
242 "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
243 "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
244 function=archive)
245 else:
246 engine.register_action(
247 'msvc.archive',
248 '''{rm} "$(<[1])"
249 $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=
250 "$(>)"
251 $(LIBRARIES_MENTIONED_BY_FILE)
252 "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
253 "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"'''.format(rm=common.rm_command()),
254 function=archive)
255
256 # For the assembler the following options are turned on by default:
257 #
258 # -Zp4 align structures to 4 bytes
259 # -Cp preserve case of user identifiers
260 # -Cx preserve case in publics, externs
261 #
262 engine.register_action(
263 'msvc.compile.asm',
264 '$(.ASM) -c -Zp4 -Cp -Cx -D$(DEFINES) $(ASMFLAGS) $(USER_ASMFLAGS) -Fo "$(<:W)" "$(>:W)"' )
265
266
267 # Equivalent to [ on $(target) return $(prefix)$(var)$(suffix) ]. Note that $(var) can be a list.
268 def expand_target_variable(target,var,prefix=None,suffix=None):
269 list = bjam.call( 'get-target-variable', target, var )
270 return " ".join([ ("" if prefix is None else prefix) + elem + ("" if suffix is None else suffix) for elem in list ])
271
272
273 def get_rspline(targets, lang_opt):
274 result = lang_opt + '\n' + \
275 expand_target_variable(targets, 'UNDEFS' , '\n-U' ) + \
276 expand_target_variable(targets, 'CFLAGS' , '\n' ) + \
277 expand_target_variable(targets, 'C++FLAGS', '\n' ) + \
278 expand_target_variable(targets, 'OPTIONS' , '\n' ) + '\n-c' + \
279 expand_target_variable(targets, 'DEFINES' , '\n-D' , '\n' ) + \
280 expand_target_variable(targets, 'INCLUDES', '\n"-I', '"\n' )
281 bjam.call('set-target-variable', targets, 'CC_RSPLINE', result)
282
283 def compile_c(targets, sources = [], properties = None):
284 get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' )
285 get_rspline(targets, '-TC')
286 compile_c_cpp(targets,sources)
287
288 def compile_c_preprocess(targets, sources = [], properties = None):
289 get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' )
290 get_rspline(targets, '-TC')
291 preprocess_c_cpp(targets,sources)
292
293 def compile_c_pch(targets, sources = [], properties = []):
294 get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' )
295 get_rspline([targets[0]], '-TC')
296 get_rspline([targets[1]], '-TC')
297
298 toolset.flags( 'msvc', 'YLOPTION', [], ['-Yl'] )
299
300 def compile_cpp(targets,sources=[],properties=None):
301 get_rspline(targets,'-TP')
302 bjam.call('set-target-variable', targets, 'PCH_FILE', sources)
303 compile_c_cpp(targets,sources)
304
305 def compile_cpp_preprocess(targets,sources=[],properties=None):
306 get_rspline(targets,'-TP')
307 preprocess_c_cpp(targets,sources)
308
309 def compile_cpp_pch(targets,sources=[],properties=None):
310 get_rspline([targets[0]], '-TP')
311 get_rspline([targets[1]], '-TP')
312
313
314 # Action for running the C/C++ compiler without using precompiled headers.
315 #
316 # WARNING: Synchronize any changes this in action with intel-win
317 #
318 # Notes regarding PDB generation, for when we use <debug-symbols>on/<debug-store>database
319 #
320 # 1. PDB_CFLAG is only set for <debug-symbols>on/<debug-store>database, ensuring that the /Fd flag is dropped if PDB_CFLAG is empty
321 #
322 # 2. When compiling executables's source files, PDB_NAME is set on a per-source file basis by rule compile-c-c++.
323 # The linker will pull these into the executable's PDB
324 #
325 # 3. When compiling library's source files, PDB_NAME is updated to <libname>.pdb for each source file by rule archive,
326 # as in this case the compiler must be used to create a single PDB for our library.
327 #
328
329 class SetupAction:
330 def __init__(self, setup_func, function):
331 self.setup_func = setup_func
332 self.function = function
333
334 def __call__(self, targets, sources, property_set):
335 assert(callable(self.setup_func))
336 # This can modify sources.
337 action_name = self.setup_func(targets, sources, property_set)
338 # Bjam actions defined from Python have only the command
339 # to execute, and no associated jam procedural code. So
340 # passing 'property_set' to it is not necessary.
341 bjam.call("set-update-action", action_name, targets, sources, [])
342 if self.function:
343 self.function(targets, sources, property_set)
344
345 def register_setup_action(action_name,setup_function,function=None):
346 global engine
347 if action_name in engine.actions:
348 raise "Bjam action %s is already defined" % action_name
349 engine.actions[action_name] = SetupAction(setup_function, function)
350
351
352 engine.register_action('compile-c-c++',
353 '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)''',
354 bound_list=['PDB_NAME'])
355
356 def setup_compile_c_cpp_action(targets, sources, properties):
357 sources += bjam.call('get-target-variable',targets,'PCH_FILE')
358 sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
359 return 'compile-c-c++'
360
361
362 register_setup_action(
363 'msvc.compile.c',
364 setup_compile_c_cpp_action,
365 function=compile_c)
366
367 register_setup_action(
368 'msvc.compile.c++',
369 setup_compile_c_cpp_action,
370 function=compile_cpp)
371
372
373 engine.register_action('preprocess-c-c++',
374 '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)"',
375 bound_list=['PDB_NAME'])
376
377 def setup_preprocess_c_cpp_action(targets, sources, properties):
378 sources += bjam.call('get-target-variable',targets,'PCH_FILE')
379 sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
380 return 'preprocess-c-c++'
381
382 register_setup_action(
383 'msvc.compile.c.preprocess',
384 setup_preprocess_c_cpp_action,
385 function=compile_c_preprocess)
386
387 register_setup_action(
388 'msvc.compile.c++.preprocess',
389 setup_preprocess_c_cpp_action,
390 function=compile_cpp_preprocess)
391
392 def compile_c_cpp(targets,sources=None):
393 pch_header = bjam.call('get-target-variable',targets[0],'PCH_HEADER')
394 pch_file = bjam.call('get-target-variable',targets[0],'PCH_FILE')
395 if pch_header: get_manager().engine().add_dependency(targets[0],pch_header)
396 if pch_file: get_manager().engine().add_dependency(targets[0],pch_file)
397 bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb')
398
399 def preprocess_c_cpp(targets,sources=None):
400 #same as above
401 return compile_c_cpp(targets,sources)
402
403 # Action for running the C/C++ compiler using precompiled headers. In addition
404 # to whatever else it needs to compile, this action also adds a temporary source
405 # .cpp file used to compile the precompiled headers themselves.
406
407
408 engine.register_action('compile-c-c++-pch',
409 '$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" "@($(<[1]:W).cpp:E=#include "$(>[1]:D=)"\n)" $(.CC.FILTER)')
410
411 engine.register_action('compile-c-c++-pch-s',
412 '$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" $(.CC.FILTER)')
413
414 def setup_c_cpp_pch(targets, sources, properties):
415 pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
416 if pch_source:
417 sources += pch_source
418 get_manager().engine().add_dependency(targets,pch_source)
419 return 'compile-c-c++-pch-s'
420 else:
421 return 'compile-c-c++-pch'
422
423 register_setup_action(
424 'msvc.compile.c.pch',
425 setup_c_cpp_pch,
426 function=compile_c_pch)
427
428 register_setup_action(
429 'msvc.compile.c++.pch',
430 setup_c_cpp_pch,
431 function=compile_cpp_pch)
432
433
434 # See midl.py for details.
435 #
436 engine.register_action(
437 'msvc.compile.idl',
438 '''$(.IDL) /nologo @"@($(<[1]:W).rsp:E=
439 "$(>:W)"
440 -D$(DEFINES)
441 "-I$(INCLUDES:W)"
442 -U$(UNDEFS)
443 $(MIDLFLAGS)
444 /tlb "$(<[1]:W)"
445 /h "$(<[2]:W)"
446 /iid "$(<[3]:W)"
447 /proxy "$(<[4]:W)"
448 /dlldata "$(<[5]:W)")"
449 {touch} "$(<[4]:W)"
450 {touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command()))
451
452 engine.register_action(
453 'msvc.compile.mc',
454 '$(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"')
455
456 engine.register_action(
457 'msvc.compile.rc',
458 '$(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES:W)" -fo "$(<:W)" "$(>:W)"')
459
460 def link_dll(targets,sources=None,properties=None):
461 get_manager().engine().add_dependency(targets,bjam.call('get-target-variable',targets,'DEF_FILE'))
462 manifest(targets, sources, properties)
463
464 def manifest(targets,sources=None,properties=None):
465 if 'on' in properties.get('<embed-manifest>'):
466 get_manager().engine().set_update_action('msvc.manifest', targets, sources, properties)
467
468
469 # Incremental linking a DLL causes no end of problems: if the actual exports do
470 # not change, the import .lib file is never updated. Therefore, the .lib is
471 # always out-of-date and gets rebuilt every time. I am not sure that incremental
472 # linking is such a great idea in general, but in this case I am sure we do not
473 # want it.
474
475 # Windows manifest is a new way to specify dependencies on managed DotNet
476 # assemblies and Windows native DLLs. The manifests are embedded as resources
477 # and are useful in any PE target (both DLL and EXE).
478
479 if not on_cygwin():
480 engine.register_action(
481 'msvc.link',
482 '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
483 "$(>)"
484 $(LIBRARIES_MENTIONED_BY_FILE)
485 $(LIBRARIES)
486 "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
487 "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
488 if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''',
489 function=manifest,
490 bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
491
492 engine.register_action(
493 'msvc.manifest',
494 '''if exist "$(<[1]).manifest" (
495 $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
496 )''')
497
498 engine.register_action(
499 'msvc.link.dll',
500 '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
501 "$(>)"
502 $(LIBRARIES_MENTIONED_BY_FILE)
503 $(LIBRARIES)
504 "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
505 "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
506 if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''',
507 function=link_dll,
508 bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
509
510 engine.register_action(
511 'msvc.manifest.dll',
512 '''if exist "$(<[1]).manifest" (
513 $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
514 )''')
515 else:
516 engine.register_action(
517 'msvc.link',
518 '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
519 "$(>)"
520 $(LIBRARIES_MENTIONED_BY_FILE)
521 $(LIBRARIES)
522 "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
523 "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
524 function=manifest,
525 bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
526
527 engine.register_action(
528 'msvc.manifest',
529 '''if test -e "$(<[1]).manifest"; then
530 $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
531 fi''')
532
533 engine.register_action(
534 'msvc.link.dll',
535 '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
536 "$(>)"
537 $(LIBRARIES_MENTIONED_BY_FILE)
538 $(LIBRARIES)
539 "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
540 "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
541 function=link_dll,
542 bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
543
544 engine.register_action(
545 'msvc.manifest.dll',
546 '''if test -e "$(<[1]).manifest"; then
547 $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
548 fi''')
549
550
551 ################################################################################
552 #
553 # Classes.
554 #
555 ################################################################################
556
557 class MsvcPchGenerator(pch.PchGenerator):
558
559 # Inherit the __init__ method
560 def run_pch(self, project, name, prop_set, sources):
561 # Find the header in sources. Ignore any CPP sources.
562 pch_header = None
563 pch_source = None
564 for s in sources:
565 if type.is_derived(s.type(), 'H'):
566 pch_header = s
567 elif type.is_derived(s.type(), 'CPP') or type.is_derived(s.type(), 'C'):
568 pch_source = s
569
570 if not pch_header:
571 raise RuntimeError( "can not build pch without pch-header" )
572
573 # If we do not have the PCH source - that is fine. We will just create a
574 # temporary .cpp file in the action.
575 properties = prop_set.all()
576 # Passing of <pch-source> is a dirty trick, needed because
577 # non-composing generators with multiple inputs are subtly
578 # broken. For more detailed information see:
579 # https://zigzag.cs.msu.su:7813/boost.build/ticket/111
580 if pch_source:
581 properties.append(Property('pch-source',pch_source))
582 generated = Generator.run(self,project,name,property_set.create(properties),[pch_header])
583 pch_file = None
584 for g in generated:
585 if type.is_derived(g.type(), 'PCH'):
586 pch_file = g
587 result_props = []
588 if pch_header:
589 result_props.append(Property('pch-header', pch_header))
590 if pch_file:
591 result_props.append(Property('pch-file', pch_file))
592
593 return property_set.PropertySet(result_props), generated
594
595
596 ################################################################################
597 #
598 # Local rules.
599 #
600 ################################################################################
601
602 # Detects versions listed as '_known_versions' by checking registry information,
603 # environment variables & default paths. Supports both native Windows and
604 # Cygwin.
605 def auto_detect_toolset_versions():
606 if on_windows() or on_cygwin():
607 for version in _known_versions:
608 versionVarName = '__version_{}_reg'.format(version.replace('.','_'))
609 if versionVarName in globals():
610 vc_path = None
611 for x64elt in [ '', 'Wow6432Node\\' ]:
612 try:
613 with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\{}Microsoft\\{}'.format(x64elt, globals()[versionVarName])) as reg_key:
614 vc_path = _winreg.QueryValueEx(reg_key, "ProductDir")[0]
615 except:
616 pass
617 if vc_path:
618 vc_path = os.path.join(vc_path,'bin')
619 register_configuration(version,os.path.normpath(vc_path))
620
621 for i in _known_versions:
622 if not i in __versions.all():
623 register_configuration(i,default_path(i))
624
625
626 def maybe_rewrite_setup(toolset, setup_script, setup_options, version, rewrite_setup='off'):
627 """
628 Helper rule to generate a faster alternative to MSVC setup scripts.
629
630 We used to call MSVC setup scripts directly in every action, however in
631 newer MSVC versions (10.0+) they make long-lasting registry queries
632 which have a significant impact on build time.
633 """
634 result = '"{}" {}'.format(setup_script, setup_options)
635
636 # At the moment we only know how to rewrite scripts with cmd shell.
637 if os.name == 'nt' and rewrite_setup != 'off':
638 basename = os.path.basename(setup_script)
639 filename, _ = os.path.splitext(basename)
640 setup_script_id = 'b2_{}_{}_{}'.format(toolset, version, filename)
641 if setup_options:
642 setup_script_id = '{}_{}'.format(setup_script_id, setup_options)
643
644 tempdir = os.environ.get('TEMP')
645 replacement = os.path.join(tempdir, setup_script_id + '.cmd')
646 if rewrite_setup == 'always' or not os.path.exists(replacement):
647 import subprocess
648 # call the setup script and print the environment after doing so
649 p = subprocess.Popen([
650 setup_script, setup_options, '>', 'nul', '&&', 'set',
651 ], stdout=subprocess.PIPE, shell=True
652 )
653 stdout, _ = p.communicate()
654
655 diff_vars = []
656 for var in stdout.splitlines():
657 # returns a tuple of ('var-name', '=', 'value').
658 # partition is being used here (over something like .split())
659 # for two reasons:
660 # 1) an environment variable may have a value that contains an '=';
661 # .partition() will still return the correct key and value pair.
662 # 2) if the line doesn't contain an '=' at all, then the returned
663 # tuple will contain only empty strings rather than raising
664 # an exception.
665 key, _, value = var.partition('=')
666 # os.environ handles casing differences here. Usually the
667 # call to "set" above will produce pascal-cased environment
668 # variable names, so a normal python dict can't be used here.
669 # check for the existence of key in case the partitioning() above
670 # returned an empty key value pair.
671 if key and os.environ.get(key) != value:
672 diff_vars.append('SET {}={}'.format(key, value))
673
674 if diff_vars:
675 with open(replacement, 'wb') as f:
676 f.write(os.linesep.join(diff_vars))
677
678 result = '"{}"'.format(replacement)
679 else:
680 result = '"{}"'.format(replacement)
681
682 return result
683
684
685 def generate_setup_cmd(version, command, parent, options, cpu, global_setup,
686 default_global_setup_options, default_setup):
687 setup_prefix = "call "
688 setup_suffix = """ >nul\n"""
689 if on_cygwin():
690 setup_prefix = "cmd.exe /S /C call "
691 setup_suffix = " \">nul\" \"&&\" "
692
693 setup_options = ''
694 setup_cpu = feature.get_values('<setup-{}>'.format(cpu), options)
695
696 if not setup_cpu:
697 if global_setup:
698 setup_cpu = global_setup
699 # If needed we can easily add using configuration flags
700 # here for overriding which options get passed to the
701 # global setup command for which target platform:
702 # setup_options = feature.get_values('<setup-options-{}>'.format(cpu),options)
703 if not setup_options:
704 setup_options = default_global_setup_options[cpu]
705 else:
706 setup_cpu = locate_default_setup(command, parent, default_setup[cpu])
707 else:
708 setup_cpu = setup_cpu[0]
709
710 # Cygwin to Windows path translation.
711 # setup-$(c) = "\""$(setup-$(c):W)"\"" ;
712
713 # Append setup options to the setup name and add the final setup
714 # prefix & suffix.
715 rewrite = feature.get_values('<rewrite-setup-scripts>', options)
716 rewrite = rewrite[0] if rewrite else ''
717 setup = maybe_rewrite_setup(
718 'msvc', setup_cpu, setup_options, version, rewrite)
719 return '{}{}{}'.format(setup_prefix, setup, setup_suffix)
720
721
722 # Worker rule for toolset version configuration. Takes an explicit version id or
723 # nothing in case it should configure the default toolset version (the first
724 # registered one or a new 'default' one in case no toolset versions have been
725 # registered yet).
726 #
727
728 def configure_really(version=None, options=[]):
729 v = version
730 if not v:
731 # Take the first registered (i.e. auto-detected) version.
732 version = __versions.first()
733 v = version
734
735 # Note: 'version' can still be empty at this point if no versions have
736 # been auto-detected.
737 if not version:
738 version = "default"
739
740 # Version alias -> real version number.
741 version = globals().get("__version_alias_{}".format(version), version)
742
743 # Check whether the selected configuration is already in use.
744 if version in __versions.used():
745 # Allow multiple 'toolset.using' calls for the same configuration if the
746 # identical sets of options are used.
747 if options and options != __versions.get(version,'options'):
748 raise RuntimeError("MSVC toolset configuration: Toolset version '$(version)' already configured.".format(version))
749 else:
750 # Register a new configuration.
751 __versions.register(version)
752
753 # Add user-supplied to auto-detected options.
754 version_opts = __versions.get(version, 'options')
755 if (version_opts):
756 options = version_opts + options
757
758 # Mark the configuration as 'used'.
759 __versions.use(version)
760 # Generate conditions and save them.
761 conditions = common.check_init_parameters('msvc', None, ('version', v))
762 __versions.set(version, 'conditions', conditions)
763 command = feature.get_values('<command>', options)
764
765 # If version is specified, we try to search first in default paths, and
766 # only then in PATH.
767 command = common.get_invocation_command('msvc', 'cl.exe', command, default_paths(version))
768 common.handle_options('msvc', conditions, command, options)
769
770 if not version:
771 # Even if version is not explicitly specified, try to detect the
772 # version from the path.
773 # FIXME: We currently detect both Microsoft Visual Studio 9.0 and
774 # 9.0express as 9.0 here.
775 if re.search("Microsoft Visual Studio[\/\\]2017", command):
776 version = '15.0'
777 elif re.search("Microsoft Visual Studio 14", command):
778 version = '14.0'
779 elif re.search("Microsoft Visual Studio 12", command):
780 version = '12.0'
781 elif re.search("Microsoft Visual Studio 11", command):
782 version = '11.0'
783 elif re.search("Microsoft Visual Studio 10", command):
784 version = '10.0'
785 elif re.search("Microsoft Visual Studio 9", command):
786 version = '9.0'
787 elif re.search("Microsoft Visual Studio 8", command):
788 version = '8.0'
789 elif re.search("NET 2003[\/\\]VC7", command):
790 version = '7.1'
791 elif re.search("Microsoft Visual C\\+\\+ Toolkit 2003", command):
792 version = '7.1toolkit'
793 elif re.search(".NET[\/\\]VC7", command):
794 version = '7.0'
795 else:
796 version = '6.0'
797
798 # Generate and register setup command.
799
800 below_8_0 = re.search("^[67]\\.",version) != None
801
802 if below_8_0:
803 cpu = ['i386']
804 else:
805 cpu = ['i386', 'amd64', 'ia64']
806
807 setup_scripts = {}
808
809 if command:
810 # TODO: Note that if we specify a non-existant toolset version then
811 # this rule may find and use a corresponding compiler executable
812 # belonging to an incorrect toolset version. For example, if you
813 # have only MSVC 7.1 installed, have its executable on the path and
814 # specify you want Boost Build to use MSVC 9.0, then you want Boost
815 # Build to report an error but this may cause it to silently use the
816 # MSVC 7.1 compiler even though it thinks it is using the msvc-9.0
817 # toolset version.
818 command = common.get_absolute_tool_path(command)
819
820 if command:
821 parent = os.path.dirname(os.path.normpath(command))
822 # Setup will be used if the command name has been specified. If
823 # setup is not specified explicitly then a default setup script will
824 # be used instead. Setup scripts may be global or arhitecture/
825 # /platform/cpu specific. Setup options are used only in case of
826 # global setup scripts.
827
828 # Default setup scripts provided with different VC distributions:
829 #
830 # VC 7.1 had only the vcvars32.bat script specific to 32 bit i386
831 # builds. It was located in the bin folder for the regular version
832 # and in the root folder for the free VC 7.1 tools.
833 #
834 # Later 8.0 & 9.0 versions introduce separate platform specific
835 # vcvars*.bat scripts (e.g. 32 bit, 64 bit AMD or 64 bit Itanium)
836 # located in or under the bin folder. Most also include a global
837 # vcvarsall.bat helper script located in the root folder which runs
838 # one of the aforementioned vcvars*.bat scripts based on the options
839 # passed to it. So far only the version coming with some PlatformSDK
840 # distributions does not include this top level script but to
841 # support those we need to fall back to using the worker scripts
842 # directly in case the top level script can not be found.
843
844 global_setup = feature.get_values('<setup>',options)
845 if global_setup:
846 global_setup = global_setup[0]
847 else:
848 global_setup = None
849
850 if not below_8_0 and not global_setup:
851 global_setup = locate_default_setup(command,parent,'vcvarsall.bat')
852
853
854 default_setup = {
855 'amd64' : 'vcvarsx86_amd64.bat',
856 'i386' : 'vcvars32.bat',
857 'ia64' : 'vcvarsx86_ia64.bat' }
858
859 # http://msdn2.microsoft.com/en-us/library/x4d2c09s(VS.80).aspx and
860 # http://msdn2.microsoft.com/en-us/library/x4d2c09s(vs.90).aspx
861 # mention an x86_IPF option, that seems to be a documentation bug
862 # and x86_ia64 is the correct option.
863 default_global_setup_options = {
864 'amd64' : 'x86_amd64',
865 'i386' : 'x86',
866 'ia64' : 'x86_ia64' }
867
868 somehow_detect_the_itanium_platform = None
869 # When using 64-bit Windows, and targeting 64-bit, it is possible to
870 # use a native 64-bit compiler, selected by the "amd64" & "ia64"
871 # parameters to vcvarsall.bat. There are two variables we can use --
872 # PROCESSOR_ARCHITECTURE and PROCESSOR_IDENTIFIER. The first is
873 # 'x86' when running 32-bit Windows, no matter which processor is
874 # used, and 'AMD64' on 64-bit windows on x86 (either AMD64 or EM64T)
875 # Windows.
876 #
877 if re.search( 'AMD64', environ[ "PROCESSOR_ARCHITECTURE" ] ) != None:
878 default_global_setup_options[ 'amd64' ] = 'amd64'
879 # TODO: The same 'native compiler usage' should be implemented for
880 # the Itanium platform by using the "ia64" parameter. For this
881 # though we need someone with access to this platform who can find
882 # out how to correctly detect this case.
883 elif somehow_detect_the_itanium_platform:
884 default_global_setup_options[ 'ia64' ] = 'ia64'
885
886 for c in cpu:
887 setup_scripts[c] = generate_setup_cmd(
888 version, command, parent, options, c, global_setup,
889 default_global_setup_options, default_setup
890 )
891
892 # Get tool names (if any) and finish setup.
893 compiler = feature.get_values("<compiler>", options)
894 compiler = compiler[0] if compiler else 'cl'
895
896 linker = feature.get_values("<linker>", options)
897 if not linker:
898 linker = "link"
899
900 resource_compiler = feature.get_values("<resource-compiler>", options)
901 if not resource_compiler:
902 resource_compiler = "rc"
903
904 # Turn on some options for i386 assembler
905 # -coff generate COFF format object file (compatible with cl.exe output)
906 default_assembler_amd64 = 'ml64'
907 default_assembler_i386 = 'ml -coff'
908 default_assembler_ia64 = 'ias'
909
910 assembler = feature.get_values('<assembler>',options)
911
912 idl_compiler = feature.get_values('<idl-compiler>',options)
913 if not idl_compiler:
914 idl_compiler = 'midl'
915
916 mc_compiler = feature.get_values('<mc-compiler>',options)
917 if not mc_compiler:
918 mc_compiler = 'mc'
919
920 manifest_tool = feature.get_values('<manifest-tool>',options)
921 if not manifest_tool:
922 manifest_tool = 'mt'
923
924 cc_filter = feature.get_values('<compiler-filter>',options)
925
926 for c in cpu:
927 cpu_conditions = [ condition + '/' + arch for arch in globals()['__cpu_arch_{}'.format(c)] for condition in conditions ]
928
929 setup_script = setup_scripts.get(c, '')
930
931 if debug():
932 for cpu_condition in cpu_conditions:
933 print "notice: [msvc-cfg] condition: '{}', setup: '{}'".format(cpu_condition,setup_script)
934
935 cpu_assembler = assembler
936 if not cpu_assembler:
937 cpu_assembler = locals()['default_assembler_{}'.format(c)]
938
939 toolset.flags('msvc.compile', '.CC' , cpu_conditions, ['{}{} /Zm800 -nologo' .format(setup_script, compiler)])
940 toolset.flags('msvc.compile', '.RC' , cpu_conditions, ['{}{}' .format(setup_script, resource_compiler)])
941 toolset.flags('msvc.compile', '.ASM', cpu_conditions, ['{}{} -nologo' .format(setup_script, cpu_assembler)])
942 toolset.flags('msvc.link' , '.LD' , cpu_conditions, ['{}{} /NOLOGO /INCREMENTAL:NO'.format(setup_script, linker)])
943 toolset.flags('msvc.archive', '.LD' , cpu_conditions, ['{}{} /lib /NOLOGO' .format(setup_script, linker)])
944 toolset.flags('msvc.compile', '.IDL', cpu_conditions, ['{}{}' .format(setup_script, idl_compiler)])
945 toolset.flags('msvc.compile', '.MC' , cpu_conditions, ['{}{}' .format(setup_script, mc_compiler)])
946 toolset.flags('msvc.link' , '.MT' , cpu_conditions, ['{}{} -nologo' .format(setup_script, manifest_tool)])
947
948 if cc_filter:
949 toolset.flags('msvc', '.CC.FILTER', cpu_conditions, ['"|" {}'.format(cc_filter)])
950
951 # Set version-specific flags.
952 configure_version_specific('msvc', version, conditions)
953
954
955 # Returns the default installation path for the given version.
956 #
957 def default_path(version):
958 # Use auto-detected path if possible.
959 options = __versions.get(version, 'options')
960 tmp_path = None
961 if options:
962 tmp_path = feature.get_values('<command>', options)
963
964 if tmp_path:
965 tmp_path="".join(tmp_path)
966 tmp_path=os.path.dirname(tmp_path)
967 else:
968 env_var_var_name = '__version_{}_env'.format(version.replace('.','_'))
969 vc_path = None
970 if env_var_var_name in globals():
971 env_var_name = globals()[env_var_var_name]
972 if env_var_name in os.environ:
973 vc_path = environ[env_var_name]
974 if vc_path:
975 vc_path = os.path.join(vc_path,globals()['__version_{}_envpath'.format(version.replace('.','_'))])
976 tmp_path = os.path.normpath(vc_path)
977
978 var_name = '__version_{}_path'.format(version.replace('.','_'))
979 if not tmp_path and var_name in globals():
980 tmp_path = os.path.normpath(os.path.join(common.get_program_files_dir(), globals()[var_name]))
981 return tmp_path
982
983
984 # Returns either the default installation path (if 'version' is not empty) or
985 # list of all known default paths (if no version is given)
986 #
987 def default_paths(version = None):
988 possible_paths = []
989 if version:
990 path = default_path(version)
991 if path:
992 possible_paths.append(path)
993 else:
994 for i in _known_versions:
995 path = default_path(i)
996 if path:
997 possible_paths.append(path)
998 return possible_paths
999
1000
1001 class MsvcLinkingGenerator(builtin.LinkingGenerator):
1002 # Calls the base version. If necessary, also create a target for the
1003 # manifest file.specifying source's name as the name of the created
1004 # target. As result, the PCH will be named whatever.hpp.gch, and not
1005 # whatever.gch.
1006 def generated_targets(self, sources, prop_set, project, name):
1007 result = builtin.LinkingGenerator.generated_targets(self, sources, prop_set, project, name)
1008 if result:
1009 name_main = result[0].name()
1010 action = result[0].action()
1011
1012 if prop_set.get('<debug-symbols>') == 'on':
1013 # We force exact name on PDB. The reason is tagging -- the tag rule may
1014 # reasonably special case some target types, like SHARED_LIB. The tag rule
1015 # will not catch PDB, and it cannot even easily figure if PDB is paired with
1016 # SHARED_LIB or EXE or something else. Because PDB always get the
1017 # same name as the main target, with .pdb as extension, just force it.
1018 target = FileTarget(name_main.split_ext()[0]+'.pdb','PDB',project,action,True)
1019 registered_target = virtual_target.register(target)
1020 if target != registered_target:
1021 action.replace_targets(target,registered_target)
1022 result.append(registered_target)
1023 if prop_set.get('<embed-manifest>') == 'off':
1024 # Manifest is evil target. It has .manifest appened to the name of
1025 # main target, including extension. E.g. a.exe.manifest. We use 'exact'
1026 # name because to achieve this effect.
1027 target = FileTarget(name_main+'.manifest', 'MANIFEST', project, action, True)
1028 registered_target = virtual_target.register(target)
1029 if target != registered_target:
1030 action.replace_targets(target,registered_target)
1031 result.append(registered_target)
1032 return result
1033
1034
1035 # Unsafe worker rule for the register-toolset() rule. Must not be called
1036 # multiple times.
1037
1038 def register_toolset_really():
1039 feature.extend('toolset', ['msvc'])
1040
1041 # Intel and msvc supposedly have link-compatible objects.
1042 feature.subfeature( 'toolset', 'msvc', 'vendor', ['intel'], ['propagated', 'optional'])
1043
1044 # Inherit MIDL flags.
1045 toolset.inherit_flags('msvc', 'midl')
1046
1047 # Inherit MC flags.
1048 toolset.inherit_flags('msvc','mc')
1049
1050 # Dynamic runtime comes only in MT flavour.
1051 toolset.add_requirements(['<toolset>msvc,<runtime-link>shared:<threading>multi'])
1052
1053 # Declare msvc toolset specific features.
1054 feature.feature('debug-store', ['object', 'database'], ['propagated'])
1055 feature.feature('pch-source', [], ['dependency', 'free'])
1056
1057 # Declare generators.
1058
1059 # TODO: Is it possible to combine these? Make the generators
1060 # non-composing so that they do not convert each source into a separate
1061 # .rsp file.
1062 generators.register(MsvcLinkingGenerator('msvc.link', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['EXE'], ['<toolset>msvc']))
1063 generators.register(MsvcLinkingGenerator('msvc.link.dll', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['SHARED_LIB','IMPORT_LIB'], ['<toolset>msvc']))
1064
1065 builtin.register_archiver('msvc.archive', ['OBJ'], ['STATIC_LIB'], ['<toolset>msvc'])
1066 builtin.register_c_compiler('msvc.compile.c++', ['CPP'], ['OBJ'], ['<toolset>msvc'])
1067 builtin.register_c_compiler('msvc.compile.c', ['C'], ['OBJ'], ['<toolset>msvc'])
1068 builtin.register_c_compiler('msvc.compile.c++.preprocess', ['CPP'], ['PREPROCESSED_CPP'], ['<toolset>msvc'])
1069 builtin.register_c_compiler('msvc.compile.c.preprocess', ['C'], ['PREPROCESSED_C'], ['<toolset>msvc'])
1070
1071 # Using 'register-c-compiler' adds the build directory to INCLUDES.
1072 builtin.register_c_compiler('msvc.compile.rc', ['RC'], ['OBJ(%_res)'], ['<toolset>msvc'])
1073 generators.override('msvc.compile.rc', 'rc.compile.resource')
1074 generators.register_standard('msvc.compile.asm', ['ASM'], ['OBJ'], ['<toolset>msvc'])
1075
1076 builtin.register_c_compiler('msvc.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], ['<toolset>msvc'])
1077 generators.override('msvc.compile.idl', 'midl.compile.idl')
1078
1079 generators.register_standard('msvc.compile.mc', ['MC'], ['H','RC'], ['<toolset>msvc'])
1080 generators.override('msvc.compile.mc', 'mc.compile')
1081
1082 # Note: the 'H' source type will catch both '.h' and '.hpp' headers as
1083 # the latter have their HPP type derived from H. The type of compilation
1084 # is determined entirely by the destination type.
1085 generators.register(MsvcPchGenerator('msvc.compile.c.pch', False, ['H'], ['C_PCH','OBJ'], ['<pch>on', '<toolset>msvc']))
1086 generators.register(MsvcPchGenerator('msvc.compile.c++.pch', False, ['H'], ['CPP_PCH','OBJ'], ['<pch>on', '<toolset>msvc']))
1087
1088 generators.override('msvc.compile.c.pch', 'pch.default-c-pch-generator')
1089 generators.override('msvc.compile.c++.pch', 'pch.default-cpp-pch-generator')
1090
1091 toolset.flags('msvc.compile', 'PCH_FILE' , ['<pch>on'], ['<pch-file>' ])
1092 toolset.flags('msvc.compile', 'PCH_SOURCE', ['<pch>on'], ['<pch-source>'])
1093 toolset.flags('msvc.compile', 'PCH_HEADER', ['<pch>on'], ['<pch-header>'])
1094
1095 #
1096 # Declare flags for compilation.
1097 #
1098 toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>speed'], ['/O2'])
1099 toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>space'], ['/O1'])
1100
1101 toolset.flags('msvc.compile', 'CFLAGS', [ a + '/<instruction-set>' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium ], ['/G1'])
1102 toolset.flags('msvc.compile', 'CFLAGS', [ a + '/<instruction-set>' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium2 ], ['/G2'])
1103
1104 toolset.flags('msvc.compile', 'CFLAGS', ['<debug-symbols>on/<debug-store>object'], ['/Z7'])
1105 toolset.flags('msvc.compile', 'CFLAGS', ['<debug-symbols>on/<debug-store>database'], ['/Zi'])
1106 toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>off'], ['/Od'])
1107 toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>off'], ['/Ob0'])
1108 toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>on'], ['/Ob1'])
1109 toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>full'], ['/Ob2'])
1110
1111 toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>on'], ['/W3'])
1112 toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>off'], ['/W0'])
1113 toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>all'], ['/W4'])
1114 toolset.flags('msvc.compile', 'CFLAGS', ['<warnings-as-errors>on'], ['/WX'])
1115
1116 toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>off'], ['/EHs'])
1117 toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>on'], ['/EHsc'])
1118 toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>off'], ['/EHa'])
1119 toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>on'], ['/EHac'])
1120
1121 # By default 8.0 enables rtti support while prior versions disabled it. We
1122 # simply enable or disable it explicitly so we do not have to depend on this
1123 # default behaviour.
1124 toolset.flags('msvc.compile', 'CFLAGS', ['<rtti>on'], ['/GR'])
1125 toolset.flags('msvc.compile', 'CFLAGS', ['<rtti>off'], ['/GR-'])
1126 toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>off/<runtime-link>shared'], ['/MD'])
1127 toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>on/<runtime-link>shared'], ['/MDd'])
1128
1129 toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>off/<runtime-link>static/<threading>multi'], ['/MT'])
1130 toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>on/<runtime-link>static/<threading>multi'], ['/MTd'])
1131
1132 toolset.flags('msvc.compile', 'OPTIONS', [], ['<cflags>'])
1133 toolset.flags('msvc.compile.c++', 'OPTIONS', [], ['<cxxflags>'])
1134
1135 toolset.flags('msvc.compile', 'PDB_CFLAG', ['<debug-symbols>on/<debug-store>database'],['/Fd'])
1136
1137 toolset.flags('msvc.compile', 'DEFINES', [], ['<define>'])
1138 toolset.flags('msvc.compile', 'UNDEFS', [], ['<undef>'])
1139 toolset.flags('msvc.compile', 'INCLUDES', [], ['<include>'])
1140
1141 # Declare flags for the assembler.
1142 toolset.flags('msvc.compile.asm', 'USER_ASMFLAGS', [], ['<asmflags>'])
1143
1144 toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<debug-symbols>on'], ['/Zi', '/Zd'])
1145
1146 toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>on'], ['/W3'])
1147 toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>off'], ['/W0'])
1148 toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>all'], ['/W4'])
1149 toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings-as-errors>on'], ['/WX'])
1150
1151 toolset.flags('msvc.compile.asm', 'DEFINES', [], ['<define>'])
1152
1153 # Declare flags for linking.
1154 toolset.flags('msvc.link', 'PDB_LINKFLAG', ['<debug-symbols>on/<debug-store>database'], ['/PDB']) # not used yet
1155 toolset.flags('msvc.link', 'LINKFLAGS', ['<debug-symbols>on'], ['/DEBUG'])
1156 toolset.flags('msvc.link', 'DEF_FILE', [], ['<def-file>'])
1157
1158 # The linker disables the default optimizations when using /DEBUG so we
1159 # have to enable them manually for release builds with debug symbols.
1160 toolset.flags('msvc', 'LINKFLAGS', ['<debug-symbols>on/<runtime-debugging>off'], ['/OPT:REF,ICF'])
1161
1162 toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>console'], ['/subsystem:console'])
1163 toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>gui'], ['/subsystem:windows'])
1164 toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>wince'], ['/subsystem:windowsce'])
1165 toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>native'], ['/subsystem:native'])
1166 toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>auto'], ['/subsystem:posix'])
1167
1168 toolset.flags('msvc.link', 'OPTIONS', [], ['<linkflags>'])
1169 toolset.flags('msvc.link', 'LINKPATH', [], ['<library-path>'])
1170
1171 toolset.flags('msvc.link', 'FINDLIBS_ST', [], ['<find-static-library>'])
1172 toolset.flags('msvc.link', 'FINDLIBS_SA', [], ['<find-shared-library>'])
1173 toolset.flags('msvc.link', 'LIBRARY_OPTION', ['<toolset>msvc'], [''])
1174 toolset.flags('msvc.link', 'LIBRARIES_MENTIONED_BY_FILE', [], ['<library-file>'])
1175
1176 toolset.flags('msvc.archive', 'AROPTIONS', [], ['<archiveflags>'])
1177
1178
1179 # Locates the requested setup script under the given folder and returns its full
1180 # path or nothing in case the script can not be found. In case multiple scripts
1181 # are found only the first one is returned.
1182 #
1183 # TODO: There used to exist a code comment for the msvc.init rule stating that
1184 # we do not correctly detect the location of the vcvars32.bat setup script for
1185 # the free VC7.1 tools in case user explicitly provides a path. This should be
1186 # tested or simply remove this whole comment in case this toolset version is no
1187 # longer important.
1188 #
1189 def locate_default_setup(command, parent, setup_name):
1190 for setup in [os.path.join(dir,setup_name) for dir in [command,parent]]:
1191 if os.path.exists(setup):
1192 return setup
1193 return None
1194
1195
1196 # Validates given path, registers found configuration and prints debug
1197 # information about it.
1198 #
1199 def register_configuration(version, path=None):
1200 if path:
1201 command = os.path.join(path, 'cl.exe')
1202 if os.path.exists(command):
1203 if debug():
1204 print "notice: [msvc-cfg] msvc-$(version) detected, command: ''".format(version,command)
1205 __versions.register(version)
1206 __versions.set(version,'options',['<command>{}'.format(command)])
1207
1208
1209 ################################################################################
1210 #
1211 # Startup code executed when loading this module.
1212 #
1213 ################################################################################
1214
1215 # Similar to Configurations, but remembers the first registered configuration.
1216 class MSVCConfigurations(Configurations):
1217 def __init__(self):
1218 Configurations.__init__(self)
1219 self.first_ = None
1220
1221 def register(self, id):
1222 Configurations.register(self,id)
1223 if not self.first_:
1224 self.first_ = id
1225
1226 def first(self):
1227 return self.first_
1228
1229
1230 # List of all registered configurations.
1231 __versions = MSVCConfigurations()
1232
1233 # Supported CPU architectures.
1234 __cpu_arch_i386 = [
1235 '<architecture>/<address-model>',
1236 '<architecture>/<address-model>32',
1237 '<architecture>x86/<address-model>',
1238 '<architecture>x86/<address-model>32']
1239
1240 __cpu_arch_amd64 = [
1241 '<architecture>/<address-model>64',
1242 '<architecture>x86/<address-model>64']
1243
1244 __cpu_arch_ia64 = [
1245 '<architecture>ia64/<address-model>',
1246 '<architecture>ia64/<address-model>64']
1247
1248
1249 # Supported CPU types (only Itanium optimization options are supported from
1250 # VC++ 2005 on). See
1251 # http://msdn2.microsoft.com/en-us/library/h66s5s0e(vs.90).aspx for more
1252 # detailed information.
1253 __cpu_type_g5 = ['i586', 'pentium', 'pentium-mmx' ]
1254 __cpu_type_g6 = ['i686', 'pentiumpro', 'pentium2', 'pentium3', 'pentium3m', 'pentium-m', 'k6',
1255 'k6-2', 'k6-3', 'winchip-c6', 'winchip2', 'c3', 'c3-2' ]
1256 __cpu_type_em64t = ['prescott', 'nocona', 'core2', 'corei7', 'corei7-avx', 'core-avx-i', 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'merom',
1257 'merom-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale',
1258 'yorksfield', 'nehalem', 'sandy-bridge', 'ivy-bridge', 'haswell' ]
1259 __cpu_type_amd64 = ['k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona',
1260 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2' ]
1261 __cpu_type_g7 = ['pentium4', 'pentium4m', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp'
1262 'athlon-mp'] + __cpu_type_em64t + __cpu_type_amd64
1263 __cpu_type_itanium = ['itanium', 'itanium1', 'merced']
1264 __cpu_type_itanium2 = ['itanium2', 'mckinley']
1265
1266
1267 # Known toolset versions, in order of preference.
1268 _known_versions = ['15.0', '14.0', '12.0', '11.0', '10.0', '10.0express', '9.0', '9.0express', '8.0', '8.0express', '7.1', '7.1toolkit', '7.0', '6.0']
1269
1270 # Version aliases.
1271 __version_alias_6 = '6.0'
1272 __version_alias_6_5 = '6.0'
1273 __version_alias_7 = '7.0'
1274 __version_alias_8 = '8.0'
1275 __version_alias_9 = '9.0'
1276 __version_alias_10 = '10.0'
1277 __version_alias_11 = '11.0'
1278 __version_alias_12 = '12.0'
1279 __version_alias_14 = '14.0'
1280 __version_alias_15 = '15.0'
1281
1282 # Names of registry keys containing the Visual C++ installation path (relative
1283 # to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft").
1284 __version_6_0_reg = "VisualStudio\\6.0\\Setup\\Microsoft Visual C++"
1285 __version_7_0_reg = "VisualStudio\\7.0\\Setup\\VC"
1286 __version_7_1_reg = "VisualStudio\\7.1\\Setup\\VC"
1287 __version_8_0_reg = "VisualStudio\\8.0\\Setup\\VC"
1288 __version_8_0express_reg = "VCExpress\\8.0\\Setup\\VC"
1289 __version_9_0_reg = "VisualStudio\\9.0\\Setup\\VC"
1290 __version_9_0express_reg = "VCExpress\\9.0\\Setup\\VC"
1291 __version_10_0_reg = "VisualStudio\\10.0\\Setup\\VC"
1292 __version_10_0express_reg = "VCExpress\\10.0\\Setup\\VC"
1293 __version_11_0_reg = "VisualStudio\\11.0\\Setup\\VC"
1294 __version_12_0_reg = "VisualStudio\\12.0\\Setup\\VC"
1295 __version_14_0_reg = "VisualStudio\\14.0\\Setup\\VC"
1296 __version_15_0_reg = "VisualStudio\\15.0\\Setup\\VC"
1297
1298 # Visual C++ Toolkit 2003 does not store its installation path in the registry.
1299 # The environment variable 'VCToolkitInstallDir' and the default installation
1300 # path will be checked instead.
1301 __version_7_1toolkit_path = 'Microsoft Visual C++ Toolkit 2003\\bin'
1302 __version_7_1toolkit_env = 'VCToolkitInstallDir'
1303
1304 # Path to the folder containing "cl.exe" relative to the value of the
1305 # corresponding environment variable.
1306 __version_7_1toolkit_envpath = 'bin' ;
1307 #
1308 #
1309 # Auto-detect all the available msvc installations on the system.
1310 auto_detect_toolset_versions()
1311
1312 # And finally trigger the actual Boost Build toolset registration.
1313 register_toolset()