# Copyright (c) 2003 David Abrahams. # Copyright (c) 2005 Vladimir Prus. # Copyright (c) 2005 Alexey Pakhunov. # Copyright (c) 2006 Bojan Resnik. # Copyright (c) 2006 Ilya Sokolov. # Copyright (c) 2007 Rene Rivera # Copyright (c) 2008 Jurko Gospodnetic # Copyright (c) 2011 Juraj Ivancic # # Use, modification and distribution is subject to the Boost Software # License Version 1.0. (See accompanying file LICENSE_1_0.txt or # http://www.boost.org/LICENSE_1_0.txt) ################################################################################ # # MSVC Boost Build toolset module. # -------------------------------- # # All toolset versions need to have their location either auto-detected or # explicitly specified except for the special 'default' version that expects the # environment to find the needed tools or report an error. # ################################################################################ from os import environ import os.path import re import _winreg import bjam from b2.tools import common, rc, pch, builtin, mc, midl from b2.build import feature, type, toolset, generators, property_set from b2.build.property import Property from b2.util import path from b2.manager import get_manager from b2.build.generators import Generator from b2.build.toolset import flags from b2.util.utility import to_seq, on_windows from b2.tools.common import Configurations __debug = None def debug(): global __debug if __debug is None: __debug = "--debug-configuration" in bjam.variable("ARGV") return __debug # It is not yet clear what to do with Cygwin on python port. def on_cygwin(): return False type.register('MANIFEST', ['manifest']) feature.feature('embed-manifest',['on','off'], ['incidental', 'propagated']) ; type.register('PDB',['pdb']) ################################################################################ # # Public rules. # ################################################################################ # Initialize a specific toolset version configuration. As the result, path to # compiler and, possible, program names are set up, and will be used when that # version of compiler is requested. For example, you might have: # # using msvc : 6.5 : cl.exe ; # using msvc : 7.0 : Y:/foo/bar/cl.exe ; # # The version parameter may be omitted: # # using msvc : : Z:/foo/bar/cl.exe ; # # The following keywords have special meanings when specified as versions: # - all - all detected but not yet used versions will be marked as used # with their default options. # - default - this is an equivalent to an empty version. # # Depending on a supplied version, detected configurations and presence 'cl.exe' # in the path different results may be achieved. The following table describes # the possible scenarios: # # Nothing "x.y" # Passed Nothing "x.y" detected, detected, # version detected detected cl.exe in path cl.exe in path # # default Error Use "x.y" Create "default" Use "x.y" # all None Use all None Use all # x.y - Use "x.y" - Use "x.y" # a.b Error Error Create "a.b" Create "a.b" # # "x.y" - refers to a detected version; # "a.b" - refers to an undetected version. # # FIXME: Currently the command parameter and the property parameter # seem to overlap in duties. Remove this duplication. This seems to be related # to why someone started preparing to replace init with configure rules. def init(version = None, command = None, options = None): # When initialized from # using msvc : x.0 ; # we get version as a single element list i.e. ['x.0'], # but when specified from the command line we get a string i.e. 'x.0'. # We want to work with a string, so unpack the list if needed. is_single_element_list = (isinstance(version,list) and len(version) == 1) assert(version==None or isinstance(version,str) or is_single_element_list) if is_single_element_list: version = version[0] options = to_seq(options) command = to_seq(command) if command: options.extend(""+cmd for cmd in command) configure(version,options) def configure(version=None, options=None): if version == "all": if options: raise RuntimeError("MSVC toolset configuration: options should be empty when '{}' is specified.".format(version)) # Configure (i.e. mark as used) all registered versions. all_versions = __versions.all() if not all_versions: if debug(): print "notice: [msvc-cfg] Asked to configure all registered" \ "msvc toolset versions when there are none currently" \ "registered." ; else: for v in all_versions: # Note that there is no need to skip already configured # versions here as this will request configure-really rule # to configure the version using default options which will # in turn cause it to simply do nothing in case the version # has already been configured. configure_really(v) elif version == "default": configure_really(None,options) else: configure_really(version, options) def extend_conditions(conditions,exts): return [ cond + '/' + ext for cond in conditions for ext in exts ] def configure_version_specific(toolset_arg, version, conditions): # Starting with versions 7.0, the msvc compiler have the /Zc:forScope and # /Zc:wchar_t options that improve C++ standard conformance, but those # options are off by default. If we are sure that the msvc version is at # 7.*, add those options explicitly. We can be sure either if user specified # version 7.* explicitly or if we auto-detected the version ourselves. if not re.search('^6\\.', version): toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',conditions, ['/Zc:forScope','/Zc:wchar_t']) toolset.flags('{}.compile.c++'.format(toolset_arg), 'C++FLAGS',conditions, ['/wd4675']) # Explicitly disable the 'function is deprecated' warning. Some msvc # versions have a bug, causing them to emit the deprecation warning even # with /W0. toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['off']), ['/wd4996']) if re.search('^[78]\.', version): # 64-bit compatibility warning deprecated since 9.0, see # http://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['all']), ['/Wp64']) # # Processor-specific optimization. # if re.search('^[67]', version ): # 8.0 deprecates some of the options. toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['speed','space']), ['/Ogiy', '/Gs']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['speed']), ['/Ot']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['space']), ['/Os']) cpu_arch_i386_cond = extend_conditions(conditions, __cpu_arch_i386) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['']),['/GB']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['i486']),['/G4']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['' + t for t in __cpu_type_g5]), ['/G5']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['' + t for t in __cpu_type_g6]), ['/G6']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['' + t for t in __cpu_type_g7]), ['/G7']) # Improve floating-point accuracy. Otherwise, some of C++ Boost's "math" # tests will fail. toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', conditions, ['/Op']) # 7.1 and below have single-threaded static RTL. toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['off/static/single']), ['/ML']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['on/static/single']), ['/MLd']) else: # 8.0 and above adds some more options. toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/' for a in __cpu_arch_amd64]), ['/favor:blend']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/' + t for a in __cpu_arch_amd64 for t in __cpu_type_em64t]), ['/favor:EM64T']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/' + t for a in __cpu_arch_amd64 for t in __cpu_type_amd64]), ['/favor:AMD64']) # 8.0 and above only has multi-threaded static RTL. toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['off/static/single']), ['/MT']) toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['on/static/single']), ['/MTd']) # Specify target machine type so the linker will not need to guess. toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_amd64), ['/MACHINE:X64']) toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_i386), ['/MACHINE:X86']) toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_ia64), ['/MACHINE:IA64']) # Make sure that manifest will be generated even if there is no # dependencies to put there. toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', conditions, ['/MANIFEST']) # Registers this toolset including all of its flags, features & generators. Does # nothing on repeated calls. def register_toolset(): if not 'msvc' in feature.values('toolset'): register_toolset_really() engine = get_manager().engine() # this rule sets up the pdb file that will be used when generating static # libraries and the debug-store option is database, so that the compiler # puts all debug info into a single .pdb file named after the library # # Poking at source targets this way is probably not clean, but it's the # easiest approach. def archive(targets, sources=None, properties=None): bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb') # Declare action for creating static libraries. If library exists, remove it # before adding files. See # http://article.gmane.org/gmane.comp.lib.boost.build/4241 for rationale. if not on_cygwin(): engine.register_action( 'msvc.archive', '''if exist "$(<[1])" DEL "$(<[1])" $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E= "$(>)" $(LIBRARIES_MENTIONED_BY_FILE) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''', function=archive) else: engine.register_action( 'msvc.archive', '''{rm} "$(<[1])" $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E= "$(>)" $(LIBRARIES_MENTIONED_BY_FILE) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"'''.format(rm=common.rm_command()), function=archive) # For the assembler the following options are turned on by default: # # -Zp4 align structures to 4 bytes # -Cp preserve case of user identifiers # -Cx preserve case in publics, externs # engine.register_action( 'msvc.compile.asm', '$(.ASM) -c -Zp4 -Cp -Cx -D$(DEFINES) $(ASMFLAGS) $(USER_ASMFLAGS) -Fo "$(<:W)" "$(>:W)"' ) # Equivalent to [ on $(target) return $(prefix)$(var)$(suffix) ]. Note that $(var) can be a list. def expand_target_variable(target,var,prefix=None,suffix=None): list = bjam.call( 'get-target-variable', target, var ) return " ".join([ ("" if prefix is None else prefix) + elem + ("" if suffix is None else suffix) for elem in list ]) def get_rspline(targets, lang_opt): result = lang_opt + '\n' + \ expand_target_variable(targets, 'UNDEFS' , '\n-U' ) + \ expand_target_variable(targets, 'CFLAGS' , '\n' ) + \ expand_target_variable(targets, 'C++FLAGS', '\n' ) + \ expand_target_variable(targets, 'OPTIONS' , '\n' ) + '\n-c' + \ expand_target_variable(targets, 'DEFINES' , '\n-D' , '\n' ) + \ expand_target_variable(targets, 'INCLUDES', '\n"-I', '"\n' ) bjam.call('set-target-variable', targets, 'CC_RSPLINE', result) def compile_c(targets, sources = [], properties = None): get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' ) get_rspline(targets, '-TC') compile_c_cpp(targets,sources) def compile_c_preprocess(targets, sources = [], properties = None): get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' ) get_rspline(targets, '-TC') preprocess_c_cpp(targets,sources) def compile_c_pch(targets, sources = [], properties = []): get_manager().engine().set_target_variable( targets[0], 'C++FLAGS', '' ) get_rspline([targets[0]], '-TC') get_rspline([targets[1]], '-TC') toolset.flags( 'msvc', 'YLOPTION', [], ['-Yl'] ) def compile_cpp(targets,sources=[],properties=None): get_rspline(targets,'-TP') bjam.call('set-target-variable', targets, 'PCH_FILE', sources) compile_c_cpp(targets,sources) def compile_cpp_preprocess(targets,sources=[],properties=None): get_rspline(targets,'-TP') preprocess_c_cpp(targets,sources) def compile_cpp_pch(targets,sources=[],properties=None): get_rspline([targets[0]], '-TP') get_rspline([targets[1]], '-TP') # Action for running the C/C++ compiler without using precompiled headers. # # WARNING: Synchronize any changes this in action with intel-win # # Notes regarding PDB generation, for when we use on/database # # 1. PDB_CFLAG is only set for on/database, ensuring that the /Fd flag is dropped if PDB_CFLAG is empty # # 2. When compiling executables's source files, PDB_NAME is set on a per-source file basis by rule compile-c-c++. # The linker will pull these into the executable's PDB # # 3. When compiling library's source files, PDB_NAME is updated to .pdb for each source file by rule archive, # as in this case the compiler must be used to create a single PDB for our library. # class SetupAction: def __init__(self, setup_func, function): self.setup_func = setup_func self.function = function def __call__(self, targets, sources, property_set): assert(callable(self.setup_func)) # This can modify sources. action_name = self.setup_func(targets, sources, property_set) # Bjam actions defined from Python have only the command # to execute, and no associated jam procedural code. So # passing 'property_set' to it is not necessary. bjam.call("set-update-action", action_name, targets, sources, []) if self.function: self.function(targets, sources, property_set) def register_setup_action(action_name,setup_function,function=None): global engine if action_name in engine.actions: raise "Bjam action %s is already defined" % action_name engine.actions[action_name] = SetupAction(setup_function, function) engine.register_action('compile-c-c++', '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)''', bound_list=['PDB_NAME']) def setup_compile_c_cpp_action(targets, sources, properties): sources += bjam.call('get-target-variable',targets,'PCH_FILE') sources += bjam.call('get-target-variable',targets,'PCH_HEADER') return 'compile-c-c++' register_setup_action( 'msvc.compile.c', setup_compile_c_cpp_action, function=compile_c) register_setup_action( 'msvc.compile.c++', setup_compile_c_cpp_action, function=compile_cpp) engine.register_action('preprocess-c-c++', '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)"', bound_list=['PDB_NAME']) def setup_preprocess_c_cpp_action(targets, sources, properties): sources += bjam.call('get-target-variable',targets,'PCH_FILE') sources += bjam.call('get-target-variable',targets,'PCH_HEADER') return 'preprocess-c-c++' register_setup_action( 'msvc.compile.c.preprocess', setup_preprocess_c_cpp_action, function=compile_c_preprocess) register_setup_action( 'msvc.compile.c++.preprocess', setup_preprocess_c_cpp_action, function=compile_cpp_preprocess) def compile_c_cpp(targets,sources=None): pch_header = bjam.call('get-target-variable',targets[0],'PCH_HEADER') pch_file = bjam.call('get-target-variable',targets[0],'PCH_FILE') if pch_header: get_manager().engine().add_dependency(targets[0],pch_header) if pch_file: get_manager().engine().add_dependency(targets[0],pch_file) bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb') def preprocess_c_cpp(targets,sources=None): #same as above return compile_c_cpp(targets,sources) # Action for running the C/C++ compiler using precompiled headers. In addition # to whatever else it needs to compile, this action also adds a temporary source # .cpp file used to compile the precompiled headers themselves. engine.register_action('compile-c-c++-pch', '$(.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)') engine.register_action('compile-c-c++-pch-s', '$(.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)') def setup_c_cpp_pch(targets, sources, properties): pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE') if pch_source: sources += pch_source get_manager().engine().add_dependency(targets,pch_source) return 'compile-c-c++-pch-s' else: return 'compile-c-c++-pch' register_setup_action( 'msvc.compile.c.pch', setup_c_cpp_pch, function=compile_c_pch) register_setup_action( 'msvc.compile.c++.pch', setup_c_cpp_pch, function=compile_cpp_pch) # See midl.py for details. # engine.register_action( 'msvc.compile.idl', '''$(.IDL) /nologo @"@($(<[1]:W).rsp:E= "$(>:W)" -D$(DEFINES) "-I$(INCLUDES:W)" -U$(UNDEFS) $(MIDLFLAGS) /tlb "$(<[1]:W)" /h "$(<[2]:W)" /iid "$(<[3]:W)" /proxy "$(<[4]:W)" /dlldata "$(<[5]:W)")" {touch} "$(<[4]:W)" {touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command())) engine.register_action( 'msvc.compile.mc', '$(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"') engine.register_action( 'msvc.compile.rc', '$(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES:W)" -fo "$(<:W)" "$(>:W)"') def link_dll(targets,sources=None,properties=None): get_manager().engine().add_dependency(targets,bjam.call('get-target-variable',targets,'DEF_FILE')) manifest(targets, sources, properties) def manifest(targets,sources=None,properties=None): if 'on' in properties.get(''): get_manager().engine().set_update_action('msvc.manifest', targets, sources, properties) # Incremental linking a DLL causes no end of problems: if the actual exports do # not change, the import .lib file is never updated. Therefore, the .lib is # always out-of-date and gets rebuilt every time. I am not sure that incremental # linking is such a great idea in general, but in this case I am sure we do not # want it. # Windows manifest is a new way to specify dependencies on managed DotNet # assemblies and Windows native DLLs. The manifests are embedded as resources # and are useful in any PE target (both DLL and EXE). if not on_cygwin(): engine.register_action( 'msvc.link', '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E= "$(>)" $(LIBRARIES_MENTIONED_BY_FILE) $(LIBRARIES) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")" if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''', function=manifest, bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE']) engine.register_action( 'msvc.manifest', '''if exist "$(<[1]).manifest" ( $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1" )''') engine.register_action( 'msvc.link.dll', '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E= "$(>)" $(LIBRARIES_MENTIONED_BY_FILE) $(LIBRARIES) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")" if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''', function=link_dll, bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE']) engine.register_action( 'msvc.manifest.dll', '''if exist "$(<[1]).manifest" ( $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2" )''') else: engine.register_action( 'msvc.link', '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E= "$(>)" $(LIBRARIES_MENTIONED_BY_FILE) $(LIBRARIES) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''', function=manifest, bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE']) engine.register_action( 'msvc.manifest', '''if test -e "$(<[1]).manifest"; then $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1" fi''') engine.register_action( 'msvc.link.dll', '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E= "$(>)" $(LIBRARIES_MENTIONED_BY_FILE) $(LIBRARIES) "$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" "$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''', function=link_dll, bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE']) engine.register_action( 'msvc.manifest.dll', '''if test -e "$(<[1]).manifest"; then $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2" fi''') ################################################################################ # # Classes. # ################################################################################ class MsvcPchGenerator(pch.PchGenerator): # Inherit the __init__ method def run_pch(self, project, name, prop_set, sources): # Find the header in sources. Ignore any CPP sources. pch_header = None pch_source = None for s in sources: if type.is_derived(s.type(), 'H'): pch_header = s elif type.is_derived(s.type(), 'CPP') or type.is_derived(s.type(), 'C'): pch_source = s if not pch_header: raise RuntimeError( "can not build pch without pch-header" ) # If we do not have the PCH source - that is fine. We will just create a # temporary .cpp file in the action. properties = prop_set.all() # Passing of is a dirty trick, needed because # non-composing generators with multiple inputs are subtly # broken. For more detailed information see: # https://zigzag.cs.msu.su:7813/boost.build/ticket/111 if pch_source: properties.append(Property('pch-source',pch_source)) generated = Generator.run(self,project,name,property_set.create(properties),[pch_header]) pch_file = None for g in generated: if type.is_derived(g.type(), 'PCH'): pch_file = g result_props = [] if pch_header: result_props.append(Property('pch-header', pch_header)) if pch_file: result_props.append(Property('pch-file', pch_file)) return property_set.PropertySet(result_props), generated ################################################################################ # # Local rules. # ################################################################################ # Detects versions listed as '_known_versions' by checking registry information, # environment variables & default paths. Supports both native Windows and # Cygwin. def auto_detect_toolset_versions(): if on_windows() or on_cygwin(): for version in _known_versions: versionVarName = '__version_{}_reg'.format(version.replace('.','_')) if versionVarName in globals(): vc_path = None for x64elt in [ '', 'Wow6432Node\\' ]: try: with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\{}Microsoft\\{}'.format(x64elt, globals()[versionVarName])) as reg_key: vc_path = _winreg.QueryValueEx(reg_key, "ProductDir")[0] except: pass if vc_path: vc_path = os.path.join(vc_path,'bin') register_configuration(version,os.path.normpath(vc_path)) for i in _known_versions: if not i in __versions.all(): register_configuration(i,default_path(i)) def maybe_rewrite_setup(toolset, setup_script, setup_options, version, rewrite_setup='off'): """ Helper rule to generate a faster alternative to MSVC setup scripts. We used to call MSVC setup scripts directly in every action, however in newer MSVC versions (10.0+) they make long-lasting registry queries which have a significant impact on build time. """ result = '"{}" {}'.format(setup_script, setup_options) # At the moment we only know how to rewrite scripts with cmd shell. if os.name == 'nt' and rewrite_setup != 'off': basename = os.path.basename(setup_script) filename, _ = os.path.splitext(basename) setup_script_id = 'b2_{}_{}_{}'.format(toolset, version, filename) if setup_options: setup_script_id = '{}_{}'.format(setup_script_id, setup_options) tempdir = os.environ.get('TEMP') replacement = os.path.join(tempdir, setup_script_id + '.cmd') if rewrite_setup == 'always' or not os.path.exists(replacement): import subprocess # call the setup script and print the environment after doing so p = subprocess.Popen([ setup_script, setup_options, '>', 'nul', '&&', 'set', ], stdout=subprocess.PIPE, shell=True ) stdout, _ = p.communicate() diff_vars = [] for var in stdout.splitlines(): # returns a tuple of ('var-name', '=', 'value'). # partition is being used here (over something like .split()) # for two reasons: # 1) an environment variable may have a value that contains an '='; # .partition() will still return the correct key and value pair. # 2) if the line doesn't contain an '=' at all, then the returned # tuple will contain only empty strings rather than raising # an exception. key, _, value = var.partition('=') # os.environ handles casing differences here. Usually the # call to "set" above will produce pascal-cased environment # variable names, so a normal python dict can't be used here. # check for the existence of key in case the partitioning() above # returned an empty key value pair. if key and os.environ.get(key) != value: diff_vars.append('SET {}={}'.format(key, value)) if diff_vars: with open(replacement, 'wb') as f: f.write(os.linesep.join(diff_vars)) result = '"{}"'.format(replacement) else: result = '"{}"'.format(replacement) return result def generate_setup_cmd(version, command, parent, options, cpu, global_setup, default_global_setup_options, default_setup): setup_prefix = "call " setup_suffix = """ >nul\n""" if on_cygwin(): setup_prefix = "cmd.exe /S /C call " setup_suffix = " \">nul\" \"&&\" " setup_options = '' setup_cpu = feature.get_values(''.format(cpu), options) if not setup_cpu: if global_setup: setup_cpu = global_setup # If needed we can easily add using configuration flags # here for overriding which options get passed to the # global setup command for which target platform: # setup_options = feature.get_values(''.format(cpu),options) if not setup_options: setup_options = default_global_setup_options[cpu] else: setup_cpu = locate_default_setup(command, parent, default_setup[cpu]) else: setup_cpu = setup_cpu[0] # Cygwin to Windows path translation. # setup-$(c) = "\""$(setup-$(c):W)"\"" ; # Append setup options to the setup name and add the final setup # prefix & suffix. rewrite = feature.get_values('', options) rewrite = rewrite[0] if rewrite else '' setup = maybe_rewrite_setup( 'msvc', setup_cpu, setup_options, version, rewrite) return '{}{}{}'.format(setup_prefix, setup, setup_suffix) # Worker rule for toolset version configuration. Takes an explicit version id or # nothing in case it should configure the default toolset version (the first # registered one or a new 'default' one in case no toolset versions have been # registered yet). # def configure_really(version=None, options=[]): v = version if not v: # Take the first registered (i.e. auto-detected) version. version = __versions.first() v = version # Note: 'version' can still be empty at this point if no versions have # been auto-detected. if not version: version = "default" # Version alias -> real version number. version = globals().get("__version_alias_{}".format(version), version) # Check whether the selected configuration is already in use. if version in __versions.used(): # Allow multiple 'toolset.using' calls for the same configuration if the # identical sets of options are used. if options and options != __versions.get(version,'options'): raise RuntimeError("MSVC toolset configuration: Toolset version '$(version)' already configured.".format(version)) else: # Register a new configuration. __versions.register(version) # Add user-supplied to auto-detected options. version_opts = __versions.get(version, 'options') if (version_opts): options = version_opts + options # Mark the configuration as 'used'. __versions.use(version) # Generate conditions and save them. conditions = common.check_init_parameters('msvc', None, ('version', v)) __versions.set(version, 'conditions', conditions) command = feature.get_values('', options) # If version is specified, we try to search first in default paths, and # only then in PATH. command = common.get_invocation_command('msvc', 'cl.exe', command, default_paths(version)) common.handle_options('msvc', conditions, command, options) if not version: # Even if version is not explicitly specified, try to detect the # version from the path. # FIXME: We currently detect both Microsoft Visual Studio 9.0 and # 9.0express as 9.0 here. if re.search("Microsoft Visual Studio[\/\\]2017", command): version = '15.0' elif re.search("Microsoft Visual Studio 14", command): version = '14.0' elif re.search("Microsoft Visual Studio 12", command): version = '12.0' elif re.search("Microsoft Visual Studio 11", command): version = '11.0' elif re.search("Microsoft Visual Studio 10", command): version = '10.0' elif re.search("Microsoft Visual Studio 9", command): version = '9.0' elif re.search("Microsoft Visual Studio 8", command): version = '8.0' elif re.search("NET 2003[\/\\]VC7", command): version = '7.1' elif re.search("Microsoft Visual C\\+\\+ Toolkit 2003", command): version = '7.1toolkit' elif re.search(".NET[\/\\]VC7", command): version = '7.0' else: version = '6.0' # Generate and register setup command. below_8_0 = re.search("^[67]\\.",version) != None if below_8_0: cpu = ['i386'] else: cpu = ['i386', 'amd64', 'ia64'] setup_scripts = {} if command: # TODO: Note that if we specify a non-existant toolset version then # this rule may find and use a corresponding compiler executable # belonging to an incorrect toolset version. For example, if you # have only MSVC 7.1 installed, have its executable on the path and # specify you want Boost Build to use MSVC 9.0, then you want Boost # Build to report an error but this may cause it to silently use the # MSVC 7.1 compiler even though it thinks it is using the msvc-9.0 # toolset version. command = common.get_absolute_tool_path(command) if command: parent = os.path.dirname(os.path.normpath(command)) # Setup will be used if the command name has been specified. If # setup is not specified explicitly then a default setup script will # be used instead. Setup scripts may be global or arhitecture/ # /platform/cpu specific. Setup options are used only in case of # global setup scripts. # Default setup scripts provided with different VC distributions: # # VC 7.1 had only the vcvars32.bat script specific to 32 bit i386 # builds. It was located in the bin folder for the regular version # and in the root folder for the free VC 7.1 tools. # # Later 8.0 & 9.0 versions introduce separate platform specific # vcvars*.bat scripts (e.g. 32 bit, 64 bit AMD or 64 bit Itanium) # located in or under the bin folder. Most also include a global # vcvarsall.bat helper script located in the root folder which runs # one of the aforementioned vcvars*.bat scripts based on the options # passed to it. So far only the version coming with some PlatformSDK # distributions does not include this top level script but to # support those we need to fall back to using the worker scripts # directly in case the top level script can not be found. global_setup = feature.get_values('',options) if global_setup: global_setup = global_setup[0] else: global_setup = None if not below_8_0 and not global_setup: global_setup = locate_default_setup(command,parent,'vcvarsall.bat') default_setup = { 'amd64' : 'vcvarsx86_amd64.bat', 'i386' : 'vcvars32.bat', 'ia64' : 'vcvarsx86_ia64.bat' } # http://msdn2.microsoft.com/en-us/library/x4d2c09s(VS.80).aspx and # http://msdn2.microsoft.com/en-us/library/x4d2c09s(vs.90).aspx # mention an x86_IPF option, that seems to be a documentation bug # and x86_ia64 is the correct option. default_global_setup_options = { 'amd64' : 'x86_amd64', 'i386' : 'x86', 'ia64' : 'x86_ia64' } somehow_detect_the_itanium_platform = None # When using 64-bit Windows, and targeting 64-bit, it is possible to # use a native 64-bit compiler, selected by the "amd64" & "ia64" # parameters to vcvarsall.bat. There are two variables we can use -- # PROCESSOR_ARCHITECTURE and PROCESSOR_IDENTIFIER. The first is # 'x86' when running 32-bit Windows, no matter which processor is # used, and 'AMD64' on 64-bit windows on x86 (either AMD64 or EM64T) # Windows. # if re.search( 'AMD64', environ[ "PROCESSOR_ARCHITECTURE" ] ) != None: default_global_setup_options[ 'amd64' ] = 'amd64' # TODO: The same 'native compiler usage' should be implemented for # the Itanium platform by using the "ia64" parameter. For this # though we need someone with access to this platform who can find # out how to correctly detect this case. elif somehow_detect_the_itanium_platform: default_global_setup_options[ 'ia64' ] = 'ia64' for c in cpu: setup_scripts[c] = generate_setup_cmd( version, command, parent, options, c, global_setup, default_global_setup_options, default_setup ) # Get tool names (if any) and finish setup. compiler = feature.get_values("", options) compiler = compiler[0] if compiler else 'cl' linker = feature.get_values("", options) if not linker: linker = "link" resource_compiler = feature.get_values("", options) if not resource_compiler: resource_compiler = "rc" # Turn on some options for i386 assembler # -coff generate COFF format object file (compatible with cl.exe output) default_assembler_amd64 = 'ml64' default_assembler_i386 = 'ml -coff' default_assembler_ia64 = 'ias' assembler = feature.get_values('',options) idl_compiler = feature.get_values('',options) if not idl_compiler: idl_compiler = 'midl' mc_compiler = feature.get_values('',options) if not mc_compiler: mc_compiler = 'mc' manifest_tool = feature.get_values('',options) if not manifest_tool: manifest_tool = 'mt' cc_filter = feature.get_values('',options) for c in cpu: cpu_conditions = [ condition + '/' + arch for arch in globals()['__cpu_arch_{}'.format(c)] for condition in conditions ] setup_script = setup_scripts.get(c, '') if debug(): for cpu_condition in cpu_conditions: print "notice: [msvc-cfg] condition: '{}', setup: '{}'".format(cpu_condition,setup_script) cpu_assembler = assembler if not cpu_assembler: cpu_assembler = locals()['default_assembler_{}'.format(c)] toolset.flags('msvc.compile', '.CC' , cpu_conditions, ['{}{} /Zm800 -nologo' .format(setup_script, compiler)]) toolset.flags('msvc.compile', '.RC' , cpu_conditions, ['{}{}' .format(setup_script, resource_compiler)]) toolset.flags('msvc.compile', '.ASM', cpu_conditions, ['{}{} -nologo' .format(setup_script, cpu_assembler)]) toolset.flags('msvc.link' , '.LD' , cpu_conditions, ['{}{} /NOLOGO /INCREMENTAL:NO'.format(setup_script, linker)]) toolset.flags('msvc.archive', '.LD' , cpu_conditions, ['{}{} /lib /NOLOGO' .format(setup_script, linker)]) toolset.flags('msvc.compile', '.IDL', cpu_conditions, ['{}{}' .format(setup_script, idl_compiler)]) toolset.flags('msvc.compile', '.MC' , cpu_conditions, ['{}{}' .format(setup_script, mc_compiler)]) toolset.flags('msvc.link' , '.MT' , cpu_conditions, ['{}{} -nologo' .format(setup_script, manifest_tool)]) if cc_filter: toolset.flags('msvc', '.CC.FILTER', cpu_conditions, ['"|" {}'.format(cc_filter)]) # Set version-specific flags. configure_version_specific('msvc', version, conditions) # Returns the default installation path for the given version. # def default_path(version): # Use auto-detected path if possible. options = __versions.get(version, 'options') tmp_path = None if options: tmp_path = feature.get_values('', options) if tmp_path: tmp_path="".join(tmp_path) tmp_path=os.path.dirname(tmp_path) else: env_var_var_name = '__version_{}_env'.format(version.replace('.','_')) vc_path = None if env_var_var_name in globals(): env_var_name = globals()[env_var_var_name] if env_var_name in os.environ: vc_path = environ[env_var_name] if vc_path: vc_path = os.path.join(vc_path,globals()['__version_{}_envpath'.format(version.replace('.','_'))]) tmp_path = os.path.normpath(vc_path) var_name = '__version_{}_path'.format(version.replace('.','_')) if not tmp_path and var_name in globals(): tmp_path = os.path.normpath(os.path.join(common.get_program_files_dir(), globals()[var_name])) return tmp_path # Returns either the default installation path (if 'version' is not empty) or # list of all known default paths (if no version is given) # def default_paths(version = None): possible_paths = [] if version: path = default_path(version) if path: possible_paths.append(path) else: for i in _known_versions: path = default_path(i) if path: possible_paths.append(path) return possible_paths class MsvcLinkingGenerator(builtin.LinkingGenerator): # Calls the base version. If necessary, also create a target for the # manifest file.specifying source's name as the name of the created # target. As result, the PCH will be named whatever.hpp.gch, and not # whatever.gch. def generated_targets(self, sources, prop_set, project, name): result = builtin.LinkingGenerator.generated_targets(self, sources, prop_set, project, name) if result: name_main = result[0].name() action = result[0].action() if prop_set.get('') == 'on': # We force exact name on PDB. The reason is tagging -- the tag rule may # reasonably special case some target types, like SHARED_LIB. The tag rule # will not catch PDB, and it cannot even easily figure if PDB is paired with # SHARED_LIB or EXE or something else. Because PDB always get the # same name as the main target, with .pdb as extension, just force it. target = FileTarget(name_main.split_ext()[0]+'.pdb','PDB',project,action,True) registered_target = virtual_target.register(target) if target != registered_target: action.replace_targets(target,registered_target) result.append(registered_target) if prop_set.get('') == 'off': # Manifest is evil target. It has .manifest appened to the name of # main target, including extension. E.g. a.exe.manifest. We use 'exact' # name because to achieve this effect. target = FileTarget(name_main+'.manifest', 'MANIFEST', project, action, True) registered_target = virtual_target.register(target) if target != registered_target: action.replace_targets(target,registered_target) result.append(registered_target) return result # Unsafe worker rule for the register-toolset() rule. Must not be called # multiple times. def register_toolset_really(): feature.extend('toolset', ['msvc']) # Intel and msvc supposedly have link-compatible objects. feature.subfeature( 'toolset', 'msvc', 'vendor', ['intel'], ['propagated', 'optional']) # Inherit MIDL flags. toolset.inherit_flags('msvc', 'midl') # Inherit MC flags. toolset.inherit_flags('msvc','mc') # Dynamic runtime comes only in MT flavour. toolset.add_requirements(['msvc,shared:multi']) # Declare msvc toolset specific features. feature.feature('debug-store', ['object', 'database'], ['propagated']) feature.feature('pch-source', [], ['dependency', 'free']) # Declare generators. # TODO: Is it possible to combine these? Make the generators # non-composing so that they do not convert each source into a separate # .rsp file. generators.register(MsvcLinkingGenerator('msvc.link', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['EXE'], ['msvc'])) generators.register(MsvcLinkingGenerator('msvc.link.dll', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['SHARED_LIB','IMPORT_LIB'], ['msvc'])) builtin.register_archiver('msvc.archive', ['OBJ'], ['STATIC_LIB'], ['msvc']) builtin.register_c_compiler('msvc.compile.c++', ['CPP'], ['OBJ'], ['msvc']) builtin.register_c_compiler('msvc.compile.c', ['C'], ['OBJ'], ['msvc']) builtin.register_c_compiler('msvc.compile.c++.preprocess', ['CPP'], ['PREPROCESSED_CPP'], ['msvc']) builtin.register_c_compiler('msvc.compile.c.preprocess', ['C'], ['PREPROCESSED_C'], ['msvc']) # Using 'register-c-compiler' adds the build directory to INCLUDES. builtin.register_c_compiler('msvc.compile.rc', ['RC'], ['OBJ(%_res)'], ['msvc']) generators.override('msvc.compile.rc', 'rc.compile.resource') generators.register_standard('msvc.compile.asm', ['ASM'], ['OBJ'], ['msvc']) builtin.register_c_compiler('msvc.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], ['msvc']) generators.override('msvc.compile.idl', 'midl.compile.idl') generators.register_standard('msvc.compile.mc', ['MC'], ['H','RC'], ['msvc']) generators.override('msvc.compile.mc', 'mc.compile') # Note: the 'H' source type will catch both '.h' and '.hpp' headers as # the latter have their HPP type derived from H. The type of compilation # is determined entirely by the destination type. generators.register(MsvcPchGenerator('msvc.compile.c.pch', False, ['H'], ['C_PCH','OBJ'], ['on', 'msvc'])) generators.register(MsvcPchGenerator('msvc.compile.c++.pch', False, ['H'], ['CPP_PCH','OBJ'], ['on', 'msvc'])) generators.override('msvc.compile.c.pch', 'pch.default-c-pch-generator') generators.override('msvc.compile.c++.pch', 'pch.default-cpp-pch-generator') toolset.flags('msvc.compile', 'PCH_FILE' , ['on'], ['' ]) toolset.flags('msvc.compile', 'PCH_SOURCE', ['on'], ['']) toolset.flags('msvc.compile', 'PCH_HEADER', ['on'], ['']) # # Declare flags for compilation. # toolset.flags('msvc.compile', 'CFLAGS', ['speed'], ['/O2']) toolset.flags('msvc.compile', 'CFLAGS', ['space'], ['/O1']) toolset.flags('msvc.compile', 'CFLAGS', [ a + '/' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium ], ['/G1']) toolset.flags('msvc.compile', 'CFLAGS', [ a + '/' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium2 ], ['/G2']) toolset.flags('msvc.compile', 'CFLAGS', ['on/object'], ['/Z7']) toolset.flags('msvc.compile', 'CFLAGS', ['on/database'], ['/Zi']) toolset.flags('msvc.compile', 'CFLAGS', ['off'], ['/Od']) toolset.flags('msvc.compile', 'CFLAGS', ['off'], ['/Ob0']) toolset.flags('msvc.compile', 'CFLAGS', ['on'], ['/Ob1']) toolset.flags('msvc.compile', 'CFLAGS', ['full'], ['/Ob2']) toolset.flags('msvc.compile', 'CFLAGS', ['on'], ['/W3']) toolset.flags('msvc.compile', 'CFLAGS', ['off'], ['/W0']) toolset.flags('msvc.compile', 'CFLAGS', ['all'], ['/W4']) toolset.flags('msvc.compile', 'CFLAGS', ['on'], ['/WX']) toolset.flags('msvc.compile', 'C++FLAGS', ['on/off/off'], ['/EHs']) toolset.flags('msvc.compile', 'C++FLAGS', ['on/off/on'], ['/EHsc']) toolset.flags('msvc.compile', 'C++FLAGS', ['on/on/off'], ['/EHa']) toolset.flags('msvc.compile', 'C++FLAGS', ['on/on/on'], ['/EHac']) # By default 8.0 enables rtti support while prior versions disabled it. We # simply enable or disable it explicitly so we do not have to depend on this # default behaviour. toolset.flags('msvc.compile', 'CFLAGS', ['on'], ['/GR']) toolset.flags('msvc.compile', 'CFLAGS', ['off'], ['/GR-']) toolset.flags('msvc.compile', 'CFLAGS', ['off/shared'], ['/MD']) toolset.flags('msvc.compile', 'CFLAGS', ['on/shared'], ['/MDd']) toolset.flags('msvc.compile', 'CFLAGS', ['off/static/multi'], ['/MT']) toolset.flags('msvc.compile', 'CFLAGS', ['on/static/multi'], ['/MTd']) toolset.flags('msvc.compile', 'OPTIONS', [], ['']) toolset.flags('msvc.compile.c++', 'OPTIONS', [], ['']) toolset.flags('msvc.compile', 'PDB_CFLAG', ['on/database'],['/Fd']) toolset.flags('msvc.compile', 'DEFINES', [], ['']) toolset.flags('msvc.compile', 'UNDEFS', [], ['']) toolset.flags('msvc.compile', 'INCLUDES', [], ['']) # Declare flags for the assembler. toolset.flags('msvc.compile.asm', 'USER_ASMFLAGS', [], ['']) toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['on'], ['/Zi', '/Zd']) toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['on'], ['/W3']) toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['off'], ['/W0']) toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['all'], ['/W4']) toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['on'], ['/WX']) toolset.flags('msvc.compile.asm', 'DEFINES', [], ['']) # Declare flags for linking. toolset.flags('msvc.link', 'PDB_LINKFLAG', ['on/database'], ['/PDB']) # not used yet toolset.flags('msvc.link', 'LINKFLAGS', ['on'], ['/DEBUG']) toolset.flags('msvc.link', 'DEF_FILE', [], ['']) # The linker disables the default optimizations when using /DEBUG so we # have to enable them manually for release builds with debug symbols. toolset.flags('msvc', 'LINKFLAGS', ['on/off'], ['/OPT:REF,ICF']) toolset.flags('msvc', 'LINKFLAGS', ['console'], ['/subsystem:console']) toolset.flags('msvc', 'LINKFLAGS', ['gui'], ['/subsystem:windows']) toolset.flags('msvc', 'LINKFLAGS', ['wince'], ['/subsystem:windowsce']) toolset.flags('msvc', 'LINKFLAGS', ['native'], ['/subsystem:native']) toolset.flags('msvc', 'LINKFLAGS', ['auto'], ['/subsystem:posix']) toolset.flags('msvc.link', 'OPTIONS', [], ['']) toolset.flags('msvc.link', 'LINKPATH', [], ['']) toolset.flags('msvc.link', 'FINDLIBS_ST', [], ['']) toolset.flags('msvc.link', 'FINDLIBS_SA', [], ['']) toolset.flags('msvc.link', 'LIBRARY_OPTION', ['msvc'], ['']) toolset.flags('msvc.link', 'LIBRARIES_MENTIONED_BY_FILE', [], ['']) toolset.flags('msvc.archive', 'AROPTIONS', [], ['']) # Locates the requested setup script under the given folder and returns its full # path or nothing in case the script can not be found. In case multiple scripts # are found only the first one is returned. # # TODO: There used to exist a code comment for the msvc.init rule stating that # we do not correctly detect the location of the vcvars32.bat setup script for # the free VC7.1 tools in case user explicitly provides a path. This should be # tested or simply remove this whole comment in case this toolset version is no # longer important. # def locate_default_setup(command, parent, setup_name): for setup in [os.path.join(dir,setup_name) for dir in [command,parent]]: if os.path.exists(setup): return setup return None # Validates given path, registers found configuration and prints debug # information about it. # def register_configuration(version, path=None): if path: command = os.path.join(path, 'cl.exe') if os.path.exists(command): if debug(): print "notice: [msvc-cfg] msvc-$(version) detected, command: ''".format(version,command) __versions.register(version) __versions.set(version,'options',['{}'.format(command)]) ################################################################################ # # Startup code executed when loading this module. # ################################################################################ # Similar to Configurations, but remembers the first registered configuration. class MSVCConfigurations(Configurations): def __init__(self): Configurations.__init__(self) self.first_ = None def register(self, id): Configurations.register(self,id) if not self.first_: self.first_ = id def first(self): return self.first_ # List of all registered configurations. __versions = MSVCConfigurations() # Supported CPU architectures. __cpu_arch_i386 = [ '/', '/32', 'x86/', 'x86/32'] __cpu_arch_amd64 = [ '/64', 'x86/64'] __cpu_arch_ia64 = [ 'ia64/', 'ia64/64'] # Supported CPU types (only Itanium optimization options are supported from # VC++ 2005 on). See # http://msdn2.microsoft.com/en-us/library/h66s5s0e(vs.90).aspx for more # detailed information. __cpu_type_g5 = ['i586', 'pentium', 'pentium-mmx' ] __cpu_type_g6 = ['i686', 'pentiumpro', 'pentium2', 'pentium3', 'pentium3m', 'pentium-m', 'k6', 'k6-2', 'k6-3', 'winchip-c6', 'winchip2', 'c3', 'c3-2', 'c7' ] __cpu_type_em64t = ['prescott', 'nocona', 'core2', 'corei7', 'corei7-avx', 'core-avx-i', 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'merom', 'merom-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale', 'yorksfield', 'nehalem', 'sandy-bridge', 'ivy-bridge', 'haswell', 'broadwell', 'skylake', 'skylake-avx512', 'cannonlake', 'icelake-client', 'icelake-server', 'cascadelake', 'cooperlake', 'tigerlake' ] __cpu_type_amd64 = ['k8', 'opteron', 'athlon64', 'athlon-fx', 'k8-sse3', 'opteron-sse3', 'athlon64-sse3', 'amdfam10', 'barcelona', 'bdver1', 'bdver2', 'bdver3', 'btver1', 'btver2', 'znver1', 'znver2' ] __cpu_type_g7 = ['pentium4', 'pentium4m', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp' 'athlon-mp'] + __cpu_type_em64t + __cpu_type_amd64 __cpu_type_itanium = ['itanium', 'itanium1', 'merced'] __cpu_type_itanium2 = ['itanium2', 'mckinley'] # Known toolset versions, in order of preference. _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'] # Version aliases. __version_alias_6 = '6.0' __version_alias_6_5 = '6.0' __version_alias_7 = '7.0' __version_alias_8 = '8.0' __version_alias_9 = '9.0' __version_alias_10 = '10.0' __version_alias_11 = '11.0' __version_alias_12 = '12.0' __version_alias_14 = '14.0' __version_alias_15 = '15.0' # Names of registry keys containing the Visual C++ installation path (relative # to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"). __version_6_0_reg = "VisualStudio\\6.0\\Setup\\Microsoft Visual C++" __version_7_0_reg = "VisualStudio\\7.0\\Setup\\VC" __version_7_1_reg = "VisualStudio\\7.1\\Setup\\VC" __version_8_0_reg = "VisualStudio\\8.0\\Setup\\VC" __version_8_0express_reg = "VCExpress\\8.0\\Setup\\VC" __version_9_0_reg = "VisualStudio\\9.0\\Setup\\VC" __version_9_0express_reg = "VCExpress\\9.0\\Setup\\VC" __version_10_0_reg = "VisualStudio\\10.0\\Setup\\VC" __version_10_0express_reg = "VCExpress\\10.0\\Setup\\VC" __version_11_0_reg = "VisualStudio\\11.0\\Setup\\VC" __version_12_0_reg = "VisualStudio\\12.0\\Setup\\VC" __version_14_0_reg = "VisualStudio\\14.0\\Setup\\VC" __version_15_0_reg = "VisualStudio\\15.0\\Setup\\VC" # Visual C++ Toolkit 2003 does not store its installation path in the registry. # The environment variable 'VCToolkitInstallDir' and the default installation # path will be checked instead. __version_7_1toolkit_path = 'Microsoft Visual C++ Toolkit 2003\\bin' __version_7_1toolkit_env = 'VCToolkitInstallDir' # Path to the folder containing "cl.exe" relative to the value of the # corresponding environment variable. __version_7_1toolkit_envpath = 'bin' ; # # # Auto-detect all the available msvc installations on the system. auto_detect_toolset_versions() # And finally trigger the actual Boost Build toolset registration. register_toolset()