diff --git a/msvc.jam b/msvc.jam index 05a67d062..01d21f136 100755 --- a/msvc.jam +++ b/msvc.jam @@ -10,6 +10,12 @@ import type ; import toolset : flags ; import errors : error ; import feature : feature ; +import sequence : unique ; + +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} feature.extend toolset : msvc ; @@ -28,50 +34,64 @@ feature.subfeature toolset msvc : vendor # link-incompatible ; -# Initialize the toolset +# 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 : X:/some_dir ; +# using msvc : 7.0 : Y:/some_dir ; +# using msvc : : Z:/some_dir +# If you have "msvc-6.5" in build request, the version from X: drive will be used, +# and if you put only "msvc", then drive "Z:" will be used. Note that it's not possible +# the specify that by default, version 7.0 must be used --- you should use 'using' +# without version number for that effect. +# +# version -- the msvc version which is being configured. When omitted +# the tools invoked when no explicit version is given will be configured. +# path -- the path to root directory of msvc installation. If not specified: +# - if version is given, default location for that version will be searched +# - if version is not given, default locations for 7.1, 7.0 and 6.* will +# be searched +# - if compiler is not found in default locations, PATH will be searched. +# +# When invoking tools, we'll first run vcvars32.bat from the configured path and +# then cl/link, without path. rule init ( version ? : path ? : vendor ? : setup ? compiler ? linker ? ) -{ - version ?= unspecified ; - feature.extend-subfeature toolset msvc : version : $(version) ; +{ + compiler ?= cl ; + linker ?= link ; + + if $(version) + { + feature.extend-subfeature toolset msvc : version : $(version) ; + } if $(vendor) && ( $(vendor) != intel ) { feature.extend-subfeature toolset msvc : vendor : $(vendor) ; } - vendor = $(vendor)- ; - vendor ?= "" ; - - local condition = -$(vendor)$(version) ; - condition ?= "" ; - condition = msvc$(condition) ; - + # setup will be used iff a path has been specified. If setup is # not specified, vcvars32.bat will be used instead. setup ?= vcvars32.bat ; - if ! $(path) && ! $(vendor) - { - path = [ locate $(version) ] ; - - compiler = $(compiler) ; - - local env-PATH = [ modules.peek : PATH Path path ] ; - if ! [ GLOB [ path.native [ path.join $(path) "bin" ] ] $(env-PATH) : $(compiler:E=CL).EXE ] - { - error toolset msvc $(vendor) $(version) initialization: : - couldn't find compiler \"$(compiler:E=CL)\" in PATH or "known default" - installation location \"$(default-path)\\BIN\" - : PATH= \"$(env-PATH)\" ; - } + if ! $(path) + { + setup = [ locate $(version) : $(vendor) ] ; } - - # FIXME? The 'path' can be empty here, which will give us - # empty 'setup'. See comment in 'locate' below. - setup = "call \""$(path)\\bin\\$(setup)"\" > nul" ; + else + { + # Don't bother with any searches. User has provided a path, + # and we assume it's correct. + setup = $(path)\\$(setup) ; + } + + # CONSIDER: What's the point of 'call'. Can we invoke the script directly? + setup = "call \""$(setup)"\" > nul " ; if [ os.name ] = NT { - setup = $(setup)" + setup = $(setup)" ; " ; } else @@ -81,47 +101,96 @@ rule init ( version ? : path ? : vendor ? : setup ? compiler ? linker ? ) # prefix with setup, or quoted path if any local prefix = $(setup) ; - prefix ?= \"$(path)\\BIN\\\" ; - prefix ?= "" ; - compiler ?= cl ; - linker ?= link ; - flags msvc.compile .CC $(condition) : $(prefix)$(compiler) ; - flags msvc.link .LD $(condition) : $(prefix)$(linker) ; - flags msvc.archive .LD $(condition) : $(prefix)$(linker) ; + + if $(version) + { + vendor = $(vendor)- ; + vendor ?= "" ; + + local condition = -$(vendor)$(version) ; + condition ?= "" ; + condition = msvc$(condition) ; + + flags msvc.compile .CC $(condition) : $(prefix)$(compiler) ; + flags msvc.link .LD $(condition) : $(prefix)$(linker) ; + flags msvc.archive .LD $(condition) : $(prefix)$(linker) ; + } + else + { + # When version is not specifying, we cannot form any usefull + # condition. Since subfeatures don't have default, we can't + # stick 'unspecified' as version. Therefore, just set global + # variables in this module. + .CC = $(prefix)$(compiler) ; + .LD = $(prefix)$(linker) ; + } } .CC = cl ; .LD = LINK ; -# Attempts to find the directory where the compiler is located, and returns it. +# Attempts to find the vcvars32.bat script for the relevant version, and returns the path +# to it. If path is not found, issues an error. # If there are several possibilities, returns arbitrary one, after issuing a # warning message. -local rule locate ( version ) +local rule locate ( version ? : vendor ? ) { - local v = [ MATCH ^(6|[^6].*) : $(version) ] ; - local version-6-path = "c:\\Program Files\\Microsoft Visual Studio\\VC98" ; - local version-7-path = "c:\\Program Files\\Microsoft Visual Studio .NET\\VC7" ; - local version-7.0-path = $(version-7-path) ; - local version-7.1-path = "c:\\Program Files\\Microsoft Visual Studio .NET 2003\\VC7" ; - local default-path = $(version-$(v)-path) ; - - # look for the setup program in both the system PATH and in - # its default installation location based on version - local env-PATH = [ modules.peek : PATH Path path ] ; - local PATH-setup = [ GLOB $(env-PATH) : $(setup) ] ; - local default-setup = [ GLOB $(default-path)\\bin : $(setup) ] ; + local possible-paths ; - # CONSIDER: what's the intentions here? Probably, it's meant that if - # setup script found in path is the same as setup script found - # in default location, we can invoke this script without full path. - # This probably does not work --- if we return empty path, the setup - # script won't be called at all. - if $(default-setup) && $(PATH-setup) != $(default-setup) + # Append the list of relevant default locations. + # We know default locations only for msvc, not for alternative vendors + if ! $(vendor) + { + local version-6-path = "c:\\Program Files\\Microsoft Visual Studio\\VC98" ; + local version-7-path = "c:\\Program Files\\Microsoft Visual Studio .NET\\VC7" ; + local version-7.0-path = $(version-7-path) ; + local version-7.1-path = "c:\\Program Files\\Microsoft Visual Studio .NET 2003\\VC7" ; + + if $(version) + { + local v = [ MATCH ^(6|[^6].*) : $(version) ] ; + possible-paths += $(version-$(v)-path) ; + } + else + { + possible-paths += $(version-7.1-path) $(version-7.0-path) $(version-6-path) ; + } + # The vccars32.bat is actually in "bin" directory. + possible-paths = $(possible-paths)\\bin ; + } + + # Append PATH + possible-paths += [ modules.peek : PATH Path path ] ; + + # Search now + local setup = [ GLOB $(possible-paths) : vcvars32.bat ] ; + # Try to avoid reporting ambiguity when there's several occurences + # of the same path, probably differing by case. + setup = [ unique $(setup:L) ] ; + + if $(setup[2]) { - return $(default-path) ; - } + ECHO warning: toolset msvc $(vendor) $(version) initialization: ; + ECHO "warning: several msvc installations found." ; + ECHO "$(setup:D)" ; + ECHO "warning: using the one in $(setup[1]:D)." ; + setup = $(setup[1]) ; + } + + if ! $(setup) + { + error toolset msvc $(vendor) $(version) initialization: : + couldn't find compiler in $(possible-paths) ; + } + + if $(.debug-configuration) + { + ECHO "notice: msvc $(version:E=) $(vendor:E="")" ; + ECHO "notice: found at \"$(setup:D)\"" ; + } + return $(setup) ; }