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 25from os import environ 26import os.path 27import re 28import _winreg 29 30import bjam 31 32from b2.tools import common, rc, pch, builtin, mc, midl 33from b2.build import feature, type, toolset, generators, property_set 34from b2.build.property import Property 35from b2.util import path 36from b2.manager import get_manager 37from b2.build.generators import Generator 38from b2.build.toolset import flags 39from b2.util.utility import to_seq, on_windows 40from b2.tools.common import Configurations 41 42__debug = None 43 44def 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. 52def on_cygwin(): 53 return False 54 55 56type.register('MANIFEST', ['manifest']) 57feature.feature('embed-manifest',['on','off'], ['incidental', 'propagated']) ; 58 59type.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 103def 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 121def 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 146def extend_conditions(conditions,exts): 147 return [ cond + '/' + ext for cond in conditions for ext in exts ] 148 149def 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 216def register_toolset(): 217 if not 'msvc' in feature.values('toolset'): 218 register_toolset_really() 219 220 221engine = 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. 229def 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. 235if 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) 245else: 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# 262engine.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. 268def 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 273def 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 283def 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 288def 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 293def 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 298toolset.flags( 'msvc', 'YLOPTION', [], ['-Yl'] ) 299 300def 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 305def compile_cpp_preprocess(targets,sources=[],properties=None): 306 get_rspline(targets,'-TP') 307 preprocess_c_cpp(targets,sources) 308 309def 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 329class 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 345def 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 352engine.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)''', 354bound_list=['PDB_NAME']) 355 356def 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 362register_setup_action( 363 'msvc.compile.c', 364 setup_compile_c_cpp_action, 365 function=compile_c) 366 367register_setup_action( 368 'msvc.compile.c++', 369 setup_compile_c_cpp_action, 370 function=compile_cpp) 371 372 373engine.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)"', 375bound_list=['PDB_NAME']) 376 377def 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 382register_setup_action( 383 'msvc.compile.c.preprocess', 384 setup_preprocess_c_cpp_action, 385 function=compile_c_preprocess) 386 387register_setup_action( 388 'msvc.compile.c++.preprocess', 389 setup_preprocess_c_cpp_action, 390 function=compile_cpp_preprocess) 391 392def 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 399def 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 408engine.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 411engine.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 414def 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 423register_setup_action( 424 'msvc.compile.c.pch', 425 setup_c_cpp_pch, 426 function=compile_c_pch) 427 428register_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# 436engine.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 452engine.register_action( 453 'msvc.compile.mc', 454 '$(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"') 455 456engine.register_action( 457 'msvc.compile.rc', 458 '$(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES:W)" -fo "$(<:W)" "$(>:W)"') 459 460def 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 464def 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 479if 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")" 488if %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")" 506if %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 )''') 515else: 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 557class 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. 605def 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 626def 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 685def 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 728def 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# 957def 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# 987def 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 1001class 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 1038def 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# 1189def 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# 1199def 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. 1216class 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', 'c7' ] 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', 'broadwell', 'skylake', 'skylake-avx512', 'cannonlake', 1259 'icelake-client', 'icelake-server', 'cascadelake', 'cooperlake', 'tigerlake' ] 1260__cpu_type_amd64 = ['k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona', 1261 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2', 'znver1', 'znver2' ] 1262__cpu_type_g7 = ['pentium4', 'pentium4m', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp' 1263 'athlon-mp'] + __cpu_type_em64t + __cpu_type_amd64 1264__cpu_type_itanium = ['itanium', 'itanium1', 'merced'] 1265__cpu_type_itanium2 = ['itanium2', 'mckinley'] 1266 1267 1268# Known toolset versions, in order of preference. 1269_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'] 1270 1271# Version aliases. 1272__version_alias_6 = '6.0' 1273__version_alias_6_5 = '6.0' 1274__version_alias_7 = '7.0' 1275__version_alias_8 = '8.0' 1276__version_alias_9 = '9.0' 1277__version_alias_10 = '10.0' 1278__version_alias_11 = '11.0' 1279__version_alias_12 = '12.0' 1280__version_alias_14 = '14.0' 1281__version_alias_15 = '15.0' 1282 1283# Names of registry keys containing the Visual C++ installation path (relative 1284# to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"). 1285__version_6_0_reg = "VisualStudio\\6.0\\Setup\\Microsoft Visual C++" 1286__version_7_0_reg = "VisualStudio\\7.0\\Setup\\VC" 1287__version_7_1_reg = "VisualStudio\\7.1\\Setup\\VC" 1288__version_8_0_reg = "VisualStudio\\8.0\\Setup\\VC" 1289__version_8_0express_reg = "VCExpress\\8.0\\Setup\\VC" 1290__version_9_0_reg = "VisualStudio\\9.0\\Setup\\VC" 1291__version_9_0express_reg = "VCExpress\\9.0\\Setup\\VC" 1292__version_10_0_reg = "VisualStudio\\10.0\\Setup\\VC" 1293__version_10_0express_reg = "VCExpress\\10.0\\Setup\\VC" 1294__version_11_0_reg = "VisualStudio\\11.0\\Setup\\VC" 1295__version_12_0_reg = "VisualStudio\\12.0\\Setup\\VC" 1296__version_14_0_reg = "VisualStudio\\14.0\\Setup\\VC" 1297__version_15_0_reg = "VisualStudio\\15.0\\Setup\\VC" 1298 1299# Visual C++ Toolkit 2003 does not store its installation path in the registry. 1300# The environment variable 'VCToolkitInstallDir' and the default installation 1301# path will be checked instead. 1302__version_7_1toolkit_path = 'Microsoft Visual C++ Toolkit 2003\\bin' 1303__version_7_1toolkit_env = 'VCToolkitInstallDir' 1304 1305# Path to the folder containing "cl.exe" relative to the value of the 1306# corresponding environment variable. 1307__version_7_1toolkit_envpath = 'bin' ; 1308# 1309# 1310# Auto-detect all the available msvc installations on the system. 1311auto_detect_toolset_versions() 1312 1313# And finally trigger the actual Boost Build toolset registration. 1314register_toolset() 1315