2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-15 00:52:16 +00:00
Files
build/src/tools/msvc.jam
2008-06-30 10:50:45 +00:00

1120 lines
40 KiB
Plaintext

# 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
#
# 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)
import "class" : new ;
import property ;
import generators ;
import os ;
import type ;
import toolset : flags ;
import errors ;
import feature ;
import path ;
import common ;
import rc ;
import midl ;
import mc ;
import pch ;
if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
{
.debug-configuration = true ;
}
feature.extend toolset : msvc ;
feature.subfeature toolset msvc : vendor
: intel
: propagated optional
# intel and msvc supposedly have link-compatible objects... remains
# to be seen, though ;-)
;
# List of all registered configurations
.versions = [ new configurations ] ;
# 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 <toolset>msvc,<runtime-link>shared:<threading>multi ;
RM = [ common.rm-command ] ;
nl = "
" ;
# Initialize the toolset for a specific version. 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 paramater can be ommited:
#
# using msvc : : Z:/foo/bar/cl.exe ;
#
# Two special version keywords may be supplied:
# - all - all detected versions will be registered;
# - 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
# all possible cases:
#
# 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.
#
# Note: for free VC7.1 tools, we do not correctly find vcvars32.bar when user
# explicitly provides a path.
#
rule init (
# The msvc version being configured. When omitted the tools invoked when no
# explicit version is given will be configured.
version ?
# The command used to invoke the compiler. If not specified:
# - if version is given, default location for that version will be
# searched
#
# - if version is not given, default locations for MSVC 9.0, 8.0, 7.1, 7.0
# and 6.* will be searched
#
# - if compiler is not found in the default locations, PATH will be
# searched.
: command *
# Options may include:
#
# All options shared by multiple toolset types as handled by the
# common.handle-options() rule, e.g. <cflags>, <compileflags>, <cxxflags>,
# <fflags> & <linkflags>.
#
# <assembler>
# <compiler>
# <idl-compiler>
# <linker>
# <mc-compiler>
# <resource-compiler>
# Exact tool names to be used by this msvc toolset configuration.
#
# <compiler-filter>
# Command through which to pipe the output of running the compiler.
# For example to pass the output to STLfilt.
#
# <setup>
# Global setup command to invoke before running any of the msvc tools.
# It will be passed additional option parameters depending on the actual
# target platform.
#
# <setup-amd64>
# <setup-i386>
# <setup-ia64>
# Platform specific setup command to invoke before running any of the
# msvc tools used when builing a target for a specific platform, e.g.
# when building a 32 or 64 bit executable.
: options *
)
{
if $(command)
{
options += <command>$(command) ;
}
configure $(version) : $(options) ;
}
# 'configure' is a newer version of 'init'. The parameter 'command' is passed as
# a part of the 'options' list.
#
rule configure ( version ? : options * )
{
switch $(version)
{
case all :
if $(options)
{
errors.error "msvc: options should be empty when 'all' is specified" ;
}
# Use all detected versions.
for local v in [ $(.versions).all ]
{
configure-really $(v) ;
}
case "default" :
configure-really : $(options) ;
case * :
configure-really $(version) : $(options) ;
}
}
# Supported CPU architectures.
.cpu-arch-i386 =
<architecture>/<address-model>
<architecture>/<address-model>32
<architecture>x86/<address-model>
<architecture>x86/<address-model>32 ;
.cpu-arch-amd64 =
<architecture>/<address-model>64
<architecture>x86/<address-model>64 ;
.cpu-arch-ia64 =
<architecture>ia64/<address-model>
<architecture>ia64/<address-model>64 ;
# 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.
#
local rule locate-default-setup ( command : parent : setup-name )
{
local result = [ GLOB $(command) $(parent) : $(setup-name) ] ;
if $(result[1])
{
return $(result[1]) ;
}
}
local rule configure-really ( version ? : options * )
{
# Note that if no version supplied uses the default configuration condition
# remains versionless.
local v = $(version) ;
if ! $(v)
{
# take the first detected version
version = [ $(.versions).all ] ;
version = $(version[1]) ;
v = $(version) ;
# Note: 'version' can still be empty at this point if no versions were
# detected.
version ?= "default" ;
}
# Version alias -> real version number
if $(.version-alias-$(version))
{
version = $(.version-alias-$(version)) ;
}
# Check whether selected configuration is used already
if $(version) in [ $(.versions).used ]
{
# Allow multiple 'toolset.using' calls for the same configuration if the
# identical sets of options are used.
if $(options) && ( $(options) != [ $(.versions).get $(version) : options ] )
{
errors.error "msvc: the toolset version '$(version)' already configured." ;
}
}
else
{
# Register a new configuration.
$(.versions).register $(version) ;
# Add user-supplied to auto-detected options.
options = [ $(.versions).get $(version) : options ] $(options) ;
# Mark the configuration as 'used'.
$(.versions).use $(version) ;
# Generate conditions and save them.
local conditions = [ common.check-init-parameters msvc : version $(v) ] ;
$(.versions).set $(version) : conditions : $(conditions) ;
local command = [ feature.get-values <command> : $(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) ] : $(version) ] ;
common.handle-options msvc : $(conditions) : $(command) : $(options) ;
if ! $(version)
{
# Even if version is not explicitly specified, try to detect the
# version from the path.
if [ MATCH "(Microsoft Visual Studio 9)" : $(command) ]
{
version = 9.0 ;
}
if [ MATCH "(Microsoft Visual Studio 8)" : $(command) ]
{
version = 8.0 ;
}
else if [ MATCH "(NET 2003[\/\\]VC7)" : $(command) ]
{
version = 7.1 ;
}
else if [ MATCH "(Microsoft Visual C\\+\\+ Toolkit 2003)" : $(command) ]
{
version = 7.1toolkit ;
}
else if [ MATCH "(.NET[\/\\]VC7)" : $(command) ]
{
version = 7.0 ;
}
else
{
version = 6.0 ;
}
}
# Generate and register setup command.
local below-8.0 = [ MATCH ^([67]\\.) : $(version) ] ;
local cpu = i386 amd64 ia64 ;
if $(below-8.0)
{
cpu = i386 ;
}
local setup-amd64 ;
local setup-i386 ;
local setup-ia64 ;
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 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 its using the msvc 9.0 toolset.
command = [ common.get-absolute-tool-path $(command[-1]) ] ;
local parent = [ path.make $(command) ] ;
parent = [ path.parent $(parent) ] ;
parent = [ path.native $(parent) ] ;
# 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.
local global-setup = [ feature.get-values <setup> : $(options) ] ;
global-setup = $(global-setup[1]) ;
if ! $(below-8.0)
{
global-setup ?= [ locate-default-setup $(command) : $(parent) : vcvarsall.bat ] ;
}
local default-setup-amd64 = vcvarsx86_amd64.bat ;
local default-setup-i386 = vcvars32.bat ;
local default-setup-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.
local default-global-setup-options-amd64 = x86_amd64 ;
local default-global-setup-options-i386 = x86 ;
local default-global-setup-options-ia64 = x86_ia64 ;
# 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 [ MATCH ^(AMD64) : [ os.environ PROCESSOR_ARCHITECTURE ] ]
{
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.
else if $(somehow-detect-the-itanium-platform)
{
default-global-setup-options-ia64 = ia64 ;
}
local setup-prefix = "call " ;
local setup-suffix = " >nul"$(nl) ;
if ! [ os.name ] in NT
{
setup-prefix = "cmd.exe /S /C call " ;
setup-suffix = " >nul \"&&\" " ;
}
for local c in $(cpu)
{
local setup-options ;
setup-$(c) = [ feature.get-values <setup-$(c)> : $(options) ] ;
if ! $(setup-$(c))-is-not-empty
{
if $(global-setup)-is-not-empty
{
setup-$(c) = $(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 <setup-options-$(c)> : $(options) ] ;
setup-options ?= $(default-global-setup-options-$(c)) ;
}
else
{
setup-$(c) = [ locate-default-setup $(command) : $(parent) : $(default-setup-$(c)) ] ;
}
}
# Cygwin to Windows path translation.
setup-$(c) = "\""$(setup-$(c):W)"\"" ;
# Append setup options to the setup name and add the final setup
# prefix & suffix.
setup-options ?= "" ;
setup-$(c) = $(setup-prefix)$(setup-$(c):J=" ")" "$(setup-options:J=" ")$(setup-suffix) ;
}
}
# Get tool names (if any) and finish setup.
compiler = [ feature.get-values <compiler> : $(options) ] ;
compiler ?= cl ;
linker = [ feature.get-values <linker> : $(options) ] ;
linker ?= link ;
resource-compiler = [ feature.get-values <resource-compiler> : $(options) ] ;
resource-compiler ?= rc ;
assembler = [ feature.get-values <assembler> : $(options) ] ;
assembler ?= ml ;
idl-compiler = [ feature.get-values <idl-compiler> : $(options) ] ;
idl-compiler ?= midl ;
mc-compiler = [ feature.get-values <mc-compiler> : $(options) ] ;
mc-compiler ?= mc ;
manifest-tool = mt ;
local cc-filter = [ feature.get-values <compiler-filter> : $(options) ] ;
for local c in $(cpu)
{
# Setup script is not required in some configurations.
setup-$(c) ?= "" ;
local cpu-conditions = $(conditions)/$(.cpu-arch-$(c)) ;
if $(.debug-configuration)
{
for local cpu-condition in $(cpu-conditions)
{
ECHO "msvc: condition: '$(cpu-condition)', setup: '$(setup-$(c))'" ;
}
}
toolset.flags msvc.compile .CC $(cpu-conditions) : $(setup-$(c))$(compiler) /Zm800 -nologo ;
toolset.flags msvc.compile .RC $(cpu-conditions) : $(setup-$(c))$(resource-compiler) ;
toolset.flags msvc.compile .ASM $(cpu-conditions) : $(setup-$(c))$(assembler) ;
toolset.flags msvc.link .LD $(cpu-conditions) : $(setup-$(c))$(linker) /NOLOGO /INCREMENTAL:NO ;
toolset.flags msvc.archive .LD $(cpu-conditions) : $(setup-$(c))$(linker) /lib /NOLOGO ;
toolset.flags msvc.compile .IDL $(cpu-conditions) : $(setup-$(c))$(idl-compiler) ;
toolset.flags msvc.compile .MC $(cpu-conditions) : $(setup-$(c))$(mc-compiler) ;
if ! [ os.name ] in NT
{
toolset.flags msvc.link .MT $(cpu-conditions) : $(setup-$(c))$(manifest-tool) -nologo ;
}
else
{
toolset.flags msvc.link .MT $(cpu-conditions) : $(manifest-tool) -nologo ;
}
if $(cc-filter)
{
toolset.flags msvc .CC.FILTER $(cpu-conditions) : "|" $(cc-filter) ;
}
}
# Set version-specific flags.
configure-version-specific msvc : $(version) : $(conditions) ;
}
}
# 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
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 ;
cpu-type-em64t = prescott nocona
conroe conroe-xe conroe-l allendale mermon mermon-xe kentsfield kentsfield-xe
penryn wolfdale yorksfield nehalem ;
cpu-type-amd64 = k8 opteron athlon64 athlon-fx ;
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 ;
# Sets up flag definitions dependent on the compiler version used.
# - 'version' is the version of compiler in N.M format.
# - 'conditions' is the property set to be used as flag conditions.
# - 'toolset' is the toolset for which flag settings are to be defined.
# This makes the rule reusable for other msvc-option-compatible compilers.
#
rule configure-version-specific ( toolset : version : conditions )
{
toolset.push-checking-for-flags-module unchecked ;
# 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're sure that msvc version is at 7.*, add
# those options explicitly. We can be sure either if user specified version
# 7.* explicitly, or if the installation path contain 7.* (checked above).
if ! [ MATCH ^(6\\.) : $(version) ]
{
toolset.flags $(toolset).compile CFLAGS $(conditions) : /Zc:forScope /Zc:wchar_t ;
toolset.flags $(toolset).compile.c++ 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 $(toolset).compile CFLAGS $(conditions)/<warnings>off : /wd4996 ;
if [ MATCH ^([78]\\.) : $(version) ]
{
# 64-bit compatibility warning deprecated since 9.0, see
# http://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx
toolset.flags $(toolset).compile CFLAGS $(conditions)/<warnings>all : /Wp64 ;
}
}
#
# Processor-specific optimization
#
if [ MATCH ^([67]) : $(version) ]
{
# 8.0 deprecates some of the options.
toolset.flags $(toolset).compile CFLAGS $(conditions)/<optimization>speed $(conditions)/<optimization>space : /Ogiy /Gs ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/<optimization>speed : /Ot ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/<optimization>space : /Os ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-i386)/<instruction-set> : /GB ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-i386)/<instruction-set>i386 : /G3 ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-i386)/<instruction-set>i486 : /G4 ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-i386)/<instruction-set>$(cpu-type-g5) : /G5 ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-i386)/<instruction-set>$(cpu-type-g6) : /G6 ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-i386)/<instruction-set>$(cpu-type-g7) : /G7 ;
# Improve floating-point accuracy. Otherwise, some of C++ Boost's "math"
# tests will fail.
toolset.flags $(toolset).compile CFLAGS $(conditions) : /Op ;
# 7.1 and below have single-threaded static RTL.
toolset.flags $(toolset).compile CFLAGS $(conditions)/<runtime-debugging>off/<runtime-link>static/<threading>single : /ML ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/<runtime-debugging>on/<runtime-link>static/<threading>single : /MLd ;
}
else
{
# 8.0 and above adds some more options.
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-amd64)/<instruction-set> : /favor:blend ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-amd64)/<instruction-set>$(cpu-type-em64t) : /favor:EM64T ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/$(.cpu-arch-amd64)/<instruction-set>$(cpu-type-amd64) : /favor:AMD64 ;
# 8.0 and above only has multi-threaded static RTL.
toolset.flags $(toolset).compile CFLAGS $(conditions)/<runtime-debugging>off/<runtime-link>static/<threading>single : /MT ;
toolset.flags $(toolset).compile CFLAGS $(conditions)/<runtime-debugging>on/<runtime-link>static/<threading>single : /MTd ;
}
toolset.pop-checking-for-flags-module ;
}
# Returns the default installation path for the given version.
#
local rule default-path ( version )
{
# Use auto-detected path if possible
local path = [ feature.get-values <command> :
[ $(.versions).get $(version) : options ] ] ;
if $(path)
{
path = $(path:D) ;
}
else
{
# Check environment
if $(.version-$(version)-env)
{
local vc-path = [ os.environ $(.version-$(version)-env) ] ;
if $(vc-path)
{
vc-path = [ path.make $(vc-path) ] ;
vc-path = [ path.join $(vc-path) $(.version-$(version)-envpath) ] ;
vc-path = [ path.native $(vc-path) ] ;
path = $(vc-path) ;
}
}
# Check default path
if ! $(path) && $(.version-$(version)-path)
{
path = [ path.native [ path.join $(.ProgramFiles) $(.version-$(version)-path) ] ] ;
}
}
return $(path) ;
}
# Returns either the default installation path (if 'version' is not empty) or
# list of all known default paths (if no version is given)
#
rule default-paths ( version ? )
{
local possible-paths ;
if $(version)
{
possible-paths += [ default-path $(version) ] ;
}
else
{
for local i in $(.known-versions)
{
possible-paths += [ default-path $(i) ] ;
}
}
return $(possible-paths) ;
}
# 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-linker msvc.link : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE : <toolset>msvc ;
generators.register-linker msvc.link.dll : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB : <toolset>msvc ;
generators.register-archiver msvc.archive : OBJ : STATIC_LIB : <toolset>msvc ;
generators.register-c-compiler msvc.compile.c++ : CPP : OBJ : <toolset>msvc ;
generators.register-c-compiler msvc.compile.c : C : OBJ : <toolset>msvc ;
# Using 'register-c-compiler' adds the build directory to INCLUDES
generators.register-c-compiler msvc.compile.rc : RC : OBJ(%_res) : <toolset>msvc ;
generators.override msvc.compile.rc : rc.compile.resource ;
generators.register-standard msvc.compile.asm : ASM : OBJ : <toolset>msvc ;
generators.register-c-compiler msvc.compile.idl : IDL : MSTYPELIB H C(%_i) C(%_proxy) C(%_dlldata) : <toolset>msvc ;
generators.override msvc.compile.idl : midl.compile.idl ;
generators.register-standard msvc.compile.mc : MC : H RC : <toolset>msvc ;
generators.override msvc.compile.mc : mc.compile ;
# pch support
feature.feature pch-source : : free dependency ;
class msvc-pch-generator : pch-generator
{
import property-set ;
rule run-pch ( project name ? : property-set : sources * )
{
# Searching header and source file in the sources.
local pch-header ;
local pch-source ;
for local s in $(sources)
{
if [ type.is-derived [ $(s).type ] H ]
{
pch-header = $(s) ;
}
else if
[ type.is-derived [ $(s).type ] CPP ]
|| [ type.is-derived [ $(s).type ] C ]
{
pch-source = $(s) ;
}
}
if ! $(pch-header)
{
errors.user-error "can't build pch without pch-header" ;
}
# If we don't have PCH source - that's fine. We'll just create a
# temporary .cpp file in the action.
local generated = [ generator.run $(project) $(name)
: [ property-set.create
# Passing of <pch-source> 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
<pch-source>$(pch-source)
[ $(property-set).raw ] ]
: $(pch-header) ] ;
local pch-file ;
for local g in $(generated)
{
if [ type.is-derived [ $(g).type ] PCH ]
{
pch-file = $(g) ;
}
}
return [ property-set.create <pch-header>$(pch-header)
<pch-file>$(pch-file) ] $(generated) ;
}
}
# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The
# latter have HPP type, but HPP type is derived from H. The type of compilation
# is determined entirely by the destination type.
generators.register [ new msvc-pch-generator msvc.compile.c.pch : H : C_PCH OBJ : <pch>on <toolset>msvc ] ;
generators.register [ new msvc-pch-generator msvc.compile.c++.pch : H : CPP_PCH OBJ : <pch>on <toolset>msvc ] ;
generators.override msvc.compile.c.pch : pch.default-c-pch-generator ;
generators.override msvc.compile.c++.pch : pch.default-cpp-pch-generator ;
flags msvc.compile PCH_FILE <pch>on : <pch-file> ;
flags msvc.compile PCH_SOURCE <pch>on : <pch-source> ;
flags msvc.compile PCH_HEADER <pch>on : <pch-header> ;
#
# Declare flags and action for compilation
#
feature.feature debug-store : object database : propagated ;
flags msvc.compile CFLAGS <optimization>speed : /O2 ;
flags msvc.compile CFLAGS <optimization>space : /O1 ;
flags msvc.compile CFLAGS $(.cpu-arch-ia64)/<instruction-set>$(cpu-type-itanium) : /G1 ;
flags msvc.compile CFLAGS $(.cpu-arch-ia64)/<instruction-set>$(cpu-type-itanium2) : /G2 ;
flags msvc.compile CFLAGS <debug-symbols>on/<debug-store>object : /Z7 ;
flags msvc.compile CFLAGS <debug-symbols>on/<debug-store>database : /Zi ;
flags msvc.compile CFLAGS <optimization>off : /Od ;
flags msvc.compile CFLAGS <inlining>off : /Ob0 ;
flags msvc.compile CFLAGS <inlining>on : /Ob1 ;
flags msvc.compile CFLAGS <inlining>full : /Ob2 ;
flags msvc.compile CFLAGS <warnings>on : /W3 ;
flags msvc.compile CFLAGS <warnings>off : /W0 ;
flags msvc.compile CFLAGS <warnings>all : /W4 ;
flags msvc.compile CFLAGS <warnings-as-errors>on : /WX ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>off : /EHs ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>on : /EHsc ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>off : /EHa ;
flags msvc.compile C++FLAGS <exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>on : /EHac ;
# By default 8.0 enables rtti support while prior versions disabled it. We
# simply enable or disable it expliclty so we do not have to depend on this
# default behaviour.
flags msvc.compile CFLAGS <rtti>on : /GR ;
flags msvc.compile CFLAGS <rtti>off : /GR- ;
flags msvc.compile CFLAGS <runtime-debugging>off/<runtime-link>shared : /MD ;
flags msvc.compile CFLAGS <runtime-debugging>on/<runtime-link>shared : /MDd ;
flags msvc.compile CFLAGS <runtime-debugging>off/<runtime-link>static/<threading>multi : /MT ;
flags msvc.compile CFLAGS <runtime-debugging>on/<runtime-link>static/<threading>multi : /MTd ;
flags msvc.compile.c OPTIONS <cflags> : ;
flags msvc.compile.c++ OPTIONS <cxxflags> : ;
flags msvc.compile PDB_CFLAG <debug-symbols>on/<debug-store>database : /Fd ; # not used yet
flags msvc.compile DEFINES <define> ;
flags msvc.compile UNDEFS <undef> ;
flags msvc.compile INCLUDES <include> ;
rule get-rspline ( target : lang-opt )
{
CC_RSPLINE on $(target) = [ on $(target) return $(lang-opt) -U$(UNDEFS) $(CFLAGS) $(C++FLAGS) $(OPTIONS) -c $(nl)-D$(DEFINES) $(nl)\"-I$(INCLUDES)\" ] ;
}
rule compile-c-c++ ( targets + : sources * )
{
DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_HEADER) ] ;
DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_FILE) ] ;
}
actions compile-c-c++
{
$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)
}
rule compile.c ( targets + : sources * : properties * )
{
C++FLAGS on $(targets[1]) = ;
get-rspline $(targets) : -TC ;
compile-c-c++ $(<) : $(>) [ on $(<) return $(PCH_FILE) ] [ on $(<) return $(PCH_HEADER) ] ;
}
rule compile.c++ ( targets + : sources * : properties * )
{
get-rspline $(targets) : -TP ;
compile-c-c++ $(<) : $(>) [ on $(<) return $(PCH_FILE) ] [ on $(<) return $(PCH_HEADER) ] ;
}
actions compile-c-c++-pch-s
{
$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" -Yl"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" $(.CC.FILTER)
}
# Needed only to avoid messing up Emacs syntax highlighting in the messy
# N-quoted code below.
quote = "\"" ;
actions compile-c-c++-pch
{
$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" -Yl"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" "@($(<[1]:W).cpp:E=#include $(quote)$(>[1]:D=)$(quote))" $(.CC.FILTER)
}
rule compile.c.pch ( targets + : sources * : properties * )
{
C++FLAGS on $(targets[1]) = ;
get-rspline $(targets[1]) : -TC ;
get-rspline $(targets[2]) : -TC ;
local pch-source = [ on $(<) return $(PCH_SOURCE) ] ;
if $(pch-source)
{
DEPENDS $(<) : $(pch-source) ;
compile-c-c++-pch-s $(targets) : $(sources) $(pch-source) ;
}
else
{
compile-c-c++-pch $(targets) : $(sources) ;
}
}
rule compile.c++.pch ( targets + : sources * : properties * )
{
get-rspline $(targets[1]) : -TP ;
get-rspline $(targets[2]) : -TP ;
local pch-source = [ on $(<) return $(PCH_SOURCE) ] ;
if $(pch-source)
{
DEPENDS $(<) : $(pch-source) ;
compile-c-c++-pch-s $(targets) : $(sources) $(pch-source) ;
}
else
{
compile-c-c++-pch $(targets) : $(sources) ;
}
}
actions compile.rc
{
$(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES)" -fo "$(<:W)" "$(>:W)"
}
# See midl.jam for details
TOUCH_FILE = [ common.file-touch-command ] ;
actions compile.idl
{
$(.IDL) /nologo @"@($(<[1]:W).rsp:E=$(nl)"$(>:W)" $(nl)-D$(DEFINES) $(nl)"-I$(INCLUDES)" $(nl)-U$(UNDEFS) $(nl)$(MIDLFLAGS) $(nl)/tlb "$(<[1]:W)" $(nl)/h "$(<[2]:W)" $(nl)/iid "$(<[3]:W)" $(nl)/proxy "$(<[4]:W)" $(nl)/dlldata "$(<[5]:W)")"
$(TOUCH_FILE) "$(<[4]:W)"
$(TOUCH_FILE) "$(<[5]:W)"
}
# Declare flags and action for the assembler
flags msvc.compile.asm USER_ASMFLAGS <asmflags> : ;
#
# for the assembler the following options are turned on by default:
#
# -coff generate COFF format object file (compatible with cl.exe output)
# -Zp4 align structures to 4 bytes
# -Cp preserve case of user identifiers
# -Cx preserve case in publics, externs
actions compile.asm
{
$(.ASM) -nologo -c -coff -Zp4 -Cp -Cx $(USER_ASMFLAGS) -Fo "$(<:W)" "$(>:W)"
}
# Declare flags and action for linking
flags msvc.link PDB_LINKFLAG <debug-symbols>on/<debug-store>database : /PDB: ; # not used yet
flags msvc.link LINKFLAGS <debug-symbols>on : /DEBUG ;
flags msvc.link DEF_FILE <def-file> ;
# The linker disables the default optimizations when using /DEBUG. Whe have to
# enable them manually for release builds with debug symbols.
flags msvc LINKFLAGS <debug-symbols>on/<runtime-debugging>off : /OPT:REF,ICF ;
flags msvc LINKFLAGS <user-interface>console : /subsystem:console ;
flags msvc LINKFLAGS <user-interface>gui : /subsystem:windows ;
flags msvc LINKFLAGS <user-interface>wince : /subsystem:windowsce ;
flags msvc LINKFLAGS <user-interface>native : /subsystem:native ;
flags msvc LINKFLAGS <user-interface>auto : /subsystem:posix ;
flags msvc.link OPTIONS <linkflags> ;
flags msvc.link LINKPATH <library-path> ;
flags msvc.link FINDLIBS_ST <find-static-library> ;
flags msvc.link FINDLIBS_SA <find-shared-library> ;
flags msvc.link LIBRARY_OPTION <toolset>msvc : "" : unchecked ;
flags msvc.link LIBRARIES_MENTIONED_BY_FILE : <library-file> ;
flags msvc.archive AROPTIONS <archiveflags> ;
rule link.dll ( targets + : sources * : properties * )
{
DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;
}
# 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 [ os.name ] in NT
{
# The 'DEL' command would issue a message to stdout if the file does not
# exist, so need a check.
actions archive
{
if exist "$(<[1])" DEL "$(<[1])"
$(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
}
}
else
{
actions archive
{
$(RM) "$(<[1])"
$(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
}
}
# 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'm 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 [ os.name ] in NT
{
actions link bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE
{
$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)$(LIBRARIES) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%
if exist "$(<[1]).manifest" (
$(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
)
}
actions link.dll bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE
{
$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)$(LIBRARIES) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%
if exist "$(<[1]).manifest" (
$(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
)
}
}
else
{
actions link bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE
{
$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)$(LIBRARIES) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
if test -e "$(<[1]).manifest"; then
$(.MT) -manifest "$(<[1]:W).manifest" "-outputresource:$(<[1]:W);1"
fi
}
actions link.dll bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE
{
$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=$(nl)"$(>)" $(nl)$(LIBRARIES_MENTIONED_BY_FILE) $(nl)$(LIBRARIES) $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
if test -e "$(<[1]).manifest"; then
$(.MT) -manifest "$(<[1]:W).manifest" "-outputresource:$(<[1]:W);2"
fi
}
}
actions compile.mc
{
$(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"
}
#
# Autodetection code
# detects versions listed as '.known-versions' using registry, environment
# and checking default paths. Supports both native Windows and Cygwin.
#
.ProgramFiles = [ path.make [ common.get-program-files-dir ] ] ;
.known-versions = 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 ;
# Name of the registry key that contains 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" ;
# Visual C++ Toolkit 2003 do 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" ;
# Validates given path, registers found configuration and prints debug
# information about it.
#
local rule register-configuration ( version : path ? )
{
if $(path)
{
local command = [ GLOB $(path) : cl.exe ] ;
if $(command)
{
if $(.debug-configuration)
{
ECHO "notice: msvc-$(version) detected, command: '$(command)'" ;
}
$(.versions).register $(version) ;
$(.versions).set $(version) : options : <command>$(command) ;
}
}
}
if [ os.name ] in NT CYGWIN
{
# Get installation paths from the registry.
for local i in $(.known-versions)
{
if $(.version-$(i)-reg)
{
local vc-path ;
for local x in "" "Wow6432Node\\"
{
vc-path += [ W32_GETREG
"HKEY_LOCAL_MACHINE\\SOFTWARE\\"$(x)"\\Microsoft\\"$(.version-$(i)-reg)
: "ProductDir" ] ;
}
if $(vc-path)
{
vc-path = [ path.native [ path.join [ path.make-NT $(vc-path[1]) ] "bin" ] ] ;
register-configuration $(i) : $(vc-path[1]) ;
}
}
}
}
# Check environment and default installation paths.
for local i in $(.known-versions)
{
if ! $(i) in [ $(.versions).all ]
{
register-configuration $(i) : [ default-path $(i) ] ;
}
}