>From 70793f3228fcb487711703fbff1a7643fe10c28e Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig@2ndquadrant.com>
Date: Mon, 21 Jan 2013 20:45:02 +0800
Subject: [PATCH] Visual Studio 2012 (VS 11) build support by Brar Piening and
 Noah Misch

This patch introduces handling of the Windows Vista / VS 2012 setlocale()
changes and the altered contents of _locale_t; see comments in
src/backend/utils/adt/pg_locale.c and
http://www.postgresql.org/message-id/20130101025421.GA17763@tornado.leadboat.com

Review and documentation amendments by Craig Ringer
---
 doc/src/sgml/install-windows.sgml | 96 +++++++++++++++++++++++----------------
 src/backend/utils/adt/pg_locale.c | 68 +++++++++++++++++++++++++--
 src/bin/initdb/initdb.c           | 12 ++++-
 src/port/chklocale.c              | 43 ++++++++++++++----
 src/port/win32env.c               |  6 +++
 src/tools/msvc/MSBuildProject.pm  | 44 +++++++++++++++++-
 src/tools/msvc/README             |  9 ++--
 src/tools/msvc/Solution.pm        | 31 +++++++++++--
 src/tools/msvc/VSObjectFactory.pm | 14 ++++--
 src/tools/msvc/build.pl           |  2 +-
 src/tools/msvc/gendef.pl          |  1 +
 11 files changed, 256 insertions(+), 70 deletions(-)

diff --git a/doc/src/sgml/install-windows.sgml b/doc/src/sgml/install-windows.sgml
new file mode 100644
index 452cf31..ea7e687
*** a/doc/src/sgml/install-windows.sgml
--- b/doc/src/sgml/install-windows.sgml
***************
*** 19,26 ****
   <para>
    There are several different ways of building PostgreSQL on
    <productname>Windows</productname>. The simplest way to build with
!   Microsoft tools is to install a supported version of the
!   <productname>Microsoft Windows SDK</productname> and use the included
    compiler. It is also possible to build with the full
    <productname>Microsoft Visual C++ 2005, 2008 or 2010</productname>. In some cases
    that requires the installation of the <productname>Windows SDK</productname>
--- 19,26 ----
   <para>
    There are several different ways of building PostgreSQL on
    <productname>Windows</productname>. The simplest way to build with
!   Microsoft tools is to install <productname>Visual Studio Express 2012
!   for Windows Desktop</productname> and use the included
    compiler. It is also possible to build with the full
    <productname>Microsoft Visual C++ 2005, 2008 or 2010</productname>. In some cases
    that requires the installation of the <productname>Windows SDK</productname>
***************
*** 77,94 ****
    <productname>Visual Studio Express</productname> or some versions of the
    <productname>Microsoft Windows SDK</productname>. If you do not already have a
    <productname>Visual Studio</productname> environment set up, the easiest
!   way is to use the compilers in the <productname>Windows SDK</productname>,
!   which is a free download from Microsoft.
!  </para>
! 
!  <para>
!   PostgreSQL is known to support compilation using the compilers shipped with
!   <productname>Visual Studio 2005</productname> to
!   <productname>Visual Studio 2010</productname> (including Express editions),
!   as well as standalone Windows SDK releases 6.0 to 7.1.
!   64-bit PostgreSQL builds are only supported with
!   <productname>Microsoft Windows SDK</productname> version 6.0a and above or
!   <productname>Visual Studio 2008</productname> and above.
   </para>
  
   <para>
--- 77,86 ----
    <productname>Visual Studio Express</productname> or some versions of the
    <productname>Microsoft Windows SDK</productname>. If you do not already have a
    <productname>Visual Studio</productname> environment set up, the easiest
!   ways are to use the compilers in the <productname>Windows SDK 7.1</productname>
!   or for PostgreSQL 9.3 and above, those from <productname>Visual Studio Express 2012 for Windows
!   Desktop</productname>. Both are free downloads from Microsoft. See the
!   requirements section below for details and supported versionss.
   </para>
  
   <para>
*************** $ENV{PATH}=$ENV{PATH} . ';c:\some\where\
*** 140,167 ****
   <sect2>
    <title>Requirements</title>
    <para>
!    The following additional products are required to build
     <productname>PostgreSQL</productname>. Use the
     <filename>config.pl</filename> file to specify which directories the libraries
     are available in.
  
     <variablelist>
      <varlistentry>
!      <term><productname>Microsoft Windows SDK</productname></term>
!      <listitem><para>
!       It is recommended that you upgrade to the latest supported version
!       of the <productname>Microsoft Windows SDK</productname> (currently
!       version 7.1), available for download from
!       <ulink url="http://www.microsoft.com/downloads/"></>.
!      </para>
!      <para>
!       You must always include the
!       <application>Windows Headers and Libraries</application> part of the SDK.
!       If you install the <productname>Windows SDK</productname>
!       including the <application>Visual C++ Compilers</application>,
!       you don't need <productname>Visual Studio</productname> to build.
!      </para></listitem>
      </varlistentry>
  
      <varlistentry>
       <term><productname>ActiveState Perl</productname></term>
--- 132,178 ----
   <sect2>
    <title>Requirements</title>
    <para>
!    The following products are required to build
     <productname>PostgreSQL</productname>. Use the
     <filename>config.pl</filename> file to specify which directories the libraries
     are available in.
  
     <variablelist>
      <varlistentry>
!       <term><productname>Microsoft Visual Studio</productname> or <productname>Microsoft Windows SDK</productname></term>
!       <listitem>
!         <para>
!          The full list of known-working development environments is:
!         </para>
!         
!         <itemizedlist>
!           <listitem><para>9.3 and above: Microsoft Visual Studio 2012, including Express (32-bit and 64-bit cross-compile)</para></listitem>
!           <listitem><para>9.2 and above: Microsoft Windows SDK 7.1 (32-bit and 64-bit)</para></listitem>
!           <listitem><para>9.2 and above: Visual Studio 2010, including Express (32-bit only)</para></listitem>
!           <listitem><para>9.0 and above: Visual Studio 2008, including Express (32-bit only)</para></listitem>
!           <listitem><para>8.2 and above: Visual Studio Express 2005 + Microsoft Windows Server 2003 R2 Platform SDK (32-bit only)</para></listitem>
!           <listitem><para>8.2 and above: Visual Studio 2005 full version</para></listitem>
!         </itemizedlist>
!         
!         <para>
!          Note that special installation steps are required for some toolsets. Please
!          check the PostgreSQL wiki for details, as these steps can vary depending on
!          what Windows version is running, other software installed on the computer, etc.
!         </para>
! 
!         <para>
!          Some Microsoft SDKs and Visual Studio editions only include 32-bit
!          compilers.  Some of these include 64-bit cross-compilers that can be
!          activated with vcvarsall x86_x64 or vcvarsall x86_amd64 . Others have
!          no 64-bit compilation support and cannot be used to produce 64-bit
!          PostgreSQL builds.  As 32-bit builds of PostgreSQL work fine on 64-bit
!          Windows, this is not a concern for all users.   For details see the
!          supported compiler list above and the PostgreSQL wiki.
!         </para>
! 
!       </listitem>
      </varlistentry>
+       
  
      <varlistentry>
       <term><productname>ActiveState Perl</productname></term>
*************** $ENV{PATH}=$ENV{PATH} . ';c:\some\where\
*** 208,214 ****
        from <ulink url="http://www.mingw.org/wiki/MSYS"></> as part of the
        <productname>MinGW</productname> compiler suite. You can also get
        <productname>msys</productname> as part of
!       <productname>msysGit</productname> from <ulink url="http://git-scm.com/"></>.
       </para>
  
       <para>
--- 219,226 ----
        from <ulink url="http://www.mingw.org/wiki/MSYS"></> as part of the
        <productname>MinGW</productname> compiler suite. You can also get
        <productname>msys</productname> as part of
!       <productname>msysGit</productname> from <ulink url="http://git-scm.com/"></>,
!       or as part of <productname>GitHub for Windows</productname>.
       </para>
  
       <para>
*************** $ENV{PATH}=$ENV{PATH} . ';c:\some\where\
*** 248,273 ****
      <varlistentry>
       <term><productname>Diff</productname></term>
       <listitem><para>
!       Diff is required to run the regression tests, and can be downloaded
!       from <ulink url="http://gnuwin32.sourceforge.net"></>.
       </para></listitem>
      </varlistentry>
  
      <varlistentry>
       <term><productname>Gettext</productname></term>
       <listitem><para>
!       Gettext is required to build with NLS support, and can be downloaded
!       from <ulink url="http://gnuwin32.sourceforge.net"></>. Note that binaries,
!       dependencies and developer files are all needed.
       </para></listitem>
      </varlistentry>
  
      <varlistentry>
       <term><productname>MIT Kerberos</productname></term>
       <listitem><para>
!       Required for Kerberos authentication support. MIT Kerberos can be
!       downloaded from
!       <ulink url="http://web.mit.edu/Kerberos/dist/index.html"></>.
       </para></listitem>
      </varlistentry>
  
--- 260,289 ----
      <varlistentry>
       <term><productname>Diff</productname></term>
       <listitem><para>
!       Diff is required to run the regression tests. Diff is included in
!       msys, so if you have installed MinGW or Git for Windows you will
!       already have it installed. See "Bison and Flex" above for details.
!       Diff can also be downloaded from <ulink
!       url="http://gnuwin32.sourceforge.net"></>. The folder containing
!       diff must be in your PATH environment variable.
       </para></listitem>
      </varlistentry>
  
      <varlistentry>
       <term><productname>Gettext</productname></term>
       <listitem><para>
!       Gettext is required to build with NLS support. 32-bit versions can be
!       downloaded from <ulink url="http://gnuwin32.sourceforge.net"></>. Note
!       that binaries, dependencies and developer files are all needed.
       </para></listitem>
      </varlistentry>
  
      <varlistentry>
       <term><productname>MIT Kerberos</productname></term>
       <listitem><para>
!       Required for Kerberos authentication support. 32-bit versions of MIT
!       Kerberos can be downloaded from <ulink
!       url="http://web.mit.edu/Kerberos/dist/index.html"></>.
       </para></listitem>
      </varlistentry>
  
*************** $ENV{PATH}=$ENV{PATH} . ';c:\some\where\
*** 275,281 ****
       <term><productname>libxml2</productname> and
        <productname>libxslt</productname></term>
       <listitem><para>
!       Required for XML support. Binaries can be downloaded from
        <ulink url="http://zlatkovic.com/pub/libxml"></> or source from
        <ulink url="http://xmlsoft.org"></>. Note that libxml2 requires iconv,
        which is available from the same download location.
--- 291,297 ----
       <term><productname>libxml2</productname> and
        <productname>libxslt</productname></term>
       <listitem><para>
!       Required for XML support. 32-bit binaries can be downloaded from
        <ulink url="http://zlatkovic.com/pub/libxml"></> or source from
        <ulink url="http://xmlsoft.org"></>. Note that libxml2 requires iconv,
        which is available from the same download location.
*************** $ENV{PATH}=$ENV{PATH} . ';c:\some\where\
*** 285,291 ****
      <varlistentry>
       <term><productname>openssl</productname></term>
       <listitem><para>
!       Required for SSL support. Binaries can be downloaded from
        <ulink url="http://www.slproweb.com/products/Win32OpenSSL.html"></>
        or source from <ulink url="http://www.openssl.org"></>.
       </para></listitem>
--- 301,307 ----
      <varlistentry>
       <term><productname>openssl</productname></term>
       <listitem><para>
!       Required for SSL support. 32-bit binaries can be downloaded from
        <ulink url="http://www.slproweb.com/products/Win32OpenSSL.html"></>
        or source from <ulink url="http://www.openssl.org"></>.
       </para></listitem>
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
new file mode 100644
index 8fe824b..890aa19
*** a/src/backend/utils/adt/pg_locale.c
--- b/src/backend/utils/adt/pg_locale.c
*************** cache_locale_time(void)
*** 715,726 ****
  
  #if defined(WIN32) && defined(LC_MESSAGES)
  /*
!  *	Convert Windows locale name to the ISO formatted one
!  *	if possible.
   *
!  *	This function returns NULL if conversion is impossible,
!  *	otherwise returns the pointer to a static area which
!  *	contains the iso formatted locale name.
   */
  static char *
  IsoLocaleName(const char *winlocname)
--- 715,755 ----
  
  #if defined(WIN32) && defined(LC_MESSAGES)
  /*
!  * Convert a Windows setlocale() argument to a Unix-style one.
   *
!  * Regardless of platform, we install message catalogs under a Unix-style
!  * LL[_CC][.ENCODING][@VARIANT] naming convention.  Only LC_MESSAGES settings
!  * following that style will elicit localized interface strings.
!  *
!  * Before Visual Studio 2012 (msvcr110.dll), Windows setlocale() accepted "C"
!  * (but not "c") and strings of the form <Language>[_<Country>][.<CodePage>],
!  * case-insensitive.  setlocale() returns the fully-qualified form; for
!  * example, setlocale("thaI") returns "Thai_Thailand.874".  Internally,
!  * setlocale() and _create_locale() select a "locale identifier"[1] and store
!  * it in an undocumented _locale_t field.  From that LCID, we can retrieve the
!  * ISO 639 language and the ISO 3166 country.  Character encoding does not
!  * matter, because the server and client encodings govern that.
!  *
!  * Windows Vista introduced the "locale name" concept[2], closely following
!  * RFC 4646.  Locale identifiers are now deprecated.  Starting with Visual
!  * Studio 2012, setlocale() accepts locale names in addition to the strings it
!  * accepted historically.  It does not standardize them; setlocale("Th-tH")
!  * returns "Th-tH".  setlocale(category, "") still returns a traditional
!  * string.  Furthermore, msvcr110.dll changed the undocumented _locale_t
!  * content to carry locale names instead of locale identifiers.
!  *
!  * MinGW headers declare _create_locale(), but msvcrt.dll lacks that symbol.
!  * IsoLocaleName() always fails in a MinGW-built postgres.exe, so only
!  * Unix-style values of the lc_messages GUC can elicit localized messages.  In
!  * particular, every lc_messages setting that initdb can select automatically
!  * will yield only C-locale messages.  XXX This could be fixed by running the
!  * fully-qualified locale name through a lookup table.
!  *
!  * This function returns a pointer to a static buffer bearing the converted
!  * name or NULL if conversion fails.
!  *
!  * [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd373763.aspx
!  * [2] http://msdn.microsoft.com/en-us/library/windows/desktop/dd373814.aspx
   */
  static char *
  IsoLocaleName(const char *winlocname)
*************** IsoLocaleName(const char *winlocname)
*** 739,744 ****
--- 768,801 ----
  	loct = _create_locale(LC_CTYPE, winlocname);
  	if (loct != NULL)
  	{
+ #if (_MSC_VER >= 1700)			/* Visual Studio 2012 or later */
+ 		size_t		rc;
+ 		char	   *hyphen;
+ 
+ 		/* Locale names use only ASCII, any conversion locale suffices. */
+ 		rc = wchar2char(iso_lc_messages, loct->locinfo->locale_name[LC_CTYPE],
+ 						sizeof(iso_lc_messages), NULL);
+ 		_free_locale(loct);
+ 		if (rc == -1 || rc == sizeof(iso_lc_messages))
+ 			return NULL;
+ 
+ 		/*
+ 		 * Since the message catalogs sit on a case-insensitive filesystem, we
+ 		 * need not standardize letter case here.  So long as we do not ship
+ 		 * message catalogs for which it would matter, we also need not
+ 		 * translate the script/variant portion, e.g. uz-Cyrl-UZ to
+ 		 * uz_UZ@cyrillic.  Simply replace the hyphen with an underscore.
+ 		 *
+ 		 * Note that the locale name can be less-specific than the value we
+ 		 * would derive under earlier Visual Studio releases.  For example,
+ 		 * French_France.1252 yields just "fr".  This does not affect any of
+ 		 * the country-specific message catalogs available as of this writing
+ 		 * (pt_BR, zh_CN, zh_TW).
+ 		 */
+ 		hyphen = strchr(iso_lc_messages, '-');
+ 		if (hyphen)
+ 			*hyphen = '_';
+ #else
  		char		isolang[32],
  					isocrty[32];
  		LCID		lcid;
*************** IsoLocaleName(const char *winlocname)
*** 753,758 ****
--- 810,816 ----
  		if (!GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, isocrty, sizeof(isocrty)))
  			return NULL;
  		snprintf(iso_lc_messages, sizeof(iso_lc_messages) - 1, "%s_%s", isolang, isocrty);
+ #endif
  		return iso_lc_messages;
  	}
  	return NULL;
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
new file mode 100644
index 1bba426..b75d976
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
*************** find_matching_ts_config(const char *lc_t
*** 935,948 ****
  
  	/*
  	 * Convert lc_ctype to a language name by stripping everything after an
! 	 * underscore.	Just for paranoia, we also stop at '.' or '@'.
  	 */
  	if (lc_type == NULL)
  		langname = pg_strdup("");
  	else
  	{
  		ptr = langname = pg_strdup(lc_type);
! 		while (*ptr && *ptr != '_' && *ptr != '.' && *ptr != '@')
  			ptr++;
  		*ptr = '\0';
  	}
--- 935,956 ----
  
  	/*
  	 * Convert lc_ctype to a language name by stripping everything after an
! 	 * underscore (usual case) or a hyphen (Windows "locale name"; see
! 	 * comments at IsoLocaleName()).
! 	 *
! 	 * XXX Should ' ' be a stop character?  This would select "norwegian" for
! 	 * the Windows locale "Norwegian (Nynorsk)_Norway.1252".  If we do so, we
! 	 * should also accept the "nn" and "nb" Unix locales.
! 	 *
! 	 * Just for paranoia, we also stop at '.' or '@'.
  	 */
  	if (lc_type == NULL)
  		langname = pg_strdup("");
  	else
  	{
  		ptr = langname = pg_strdup(lc_type);
! 		while (*ptr &&
! 			   *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@')
  			ptr++;
  		*ptr = '\0';
  	}
diff --git a/src/port/chklocale.c b/src/port/chklocale.c
new file mode 100644
index 7e2062c..9e88938
*** a/src/port/chklocale.c
--- b/src/port/chklocale.c
*************** static const struct encoding_match encod
*** 189,214 ****
  
  #ifdef WIN32
  /*
!  * On Windows, use CP<codepage number> instead of the nl_langinfo() result
   */
  static char *
  win32_langinfo(const char *ctype)
  {
! 	char	   *r;
  	char	   *codepage;
- 	int			ln;
  
  	/*
  	 * Locale format on Win32 is <Language>_<Country>.<CodePage> . For
! 	 * example, English_USA.1252.
  	 */
  	codepage = strrchr(ctype, '.');
! 	if (!codepage)
! 		return NULL;
! 	codepage++;
! 	ln = strlen(codepage);
! 	r = malloc(ln + 3);
! 	sprintf(r, "CP%s", codepage);
  
  	return r;
  }
--- 189,237 ----
  
  #ifdef WIN32
  /*
!  * On Windows, use CP<code page number> instead of the nl_langinfo() result
!  *
!  * Visual Studio 2012 expanded the set of valid LC_CTYPE values, so have its
!  * locale machinery determine the code page.  See comments at IsoLocaleName().
!  * For other compilers, follow the locale's predictable format.
!  *
!  * Returns a malloc()'d string for the caller to free.
   */
  static char *
  win32_langinfo(const char *ctype)
  {
! 	char	   *r = NULL;
! 
! #if (_MSC_VER >= 1700)
! 	_locale_t	loct = NULL;
! 
! 	loct = _create_locale(LC_CTYPE, ctype);
! 	if (loct != NULL)
! 	{
! 		r = malloc(16);			/* excess */
! 		if (r != NULL)
! 			sprintf(r, "CP%u", loct->locinfo->lc_codepage);
! 		_free_locale(loct);
! 	}
! #else
  	char	   *codepage;
  
  	/*
  	 * Locale format on Win32 is <Language>_<Country>.<CodePage> . For
! 	 * example, English_United States.1252.
  	 */
  	codepage = strrchr(ctype, '.');
! 	if (codepage != NULL)
! 	{
! 		int			ln;
! 
! 		codepage++;
! 		ln = strlen(codepage);
! 		r = malloc(ln + 3);
! 		if (r != NULL)
! 			sprintf(r, "CP%s", codepage);
! 	}
! #endif
  
  	return r;
  }
diff --git a/src/port/win32env.c b/src/port/win32env.c
new file mode 100644
index 5f0f6f9..b5f4e8e
*** a/src/port/win32env.c
--- b/src/port/win32env.c
*************** pgwin32_putenv(const char *envval)
*** 61,66 ****
--- 61,72 ----
  			"msvcr90", 0, NULL
  		},						/* Visual Studio 2008 */
  		{
+ 			"msvcr100", 0, NULL
+ 		},						/* Visual Studio 2010 */
+ 		{
+ 			"msvcr110", 0, NULL
+ 		},						/* Visual Studio 2012 */
+ 		{
  			NULL, 0, NULL
  		}
  	};
diff --git a/src/tools/msvc/MSBuildProject.pm b/src/tools/msvc/MSBuildProject.pm
new file mode 100644
index 2e3eab6..0cafd71
*** a/src/tools/msvc/MSBuildProject.pm
--- b/src/tools/msvc/MSBuildProject.pm
***************
*** 1,7 ****
  package MSBuildProject;
  
  #
! # Package that encapsulates a MSBuild (Visual C++ 2010) project file
  #
  # src/tools/msvc/MSBuildProject.pm
  #
--- 1,7 ----
  package MSBuildProject;
  
  #
! # Package that encapsulates a MSBuild project file (Visual C++ 2010 or greater)
  #
  # src/tools/msvc/MSBuildProject.pm
  #
*************** sub new
*** 397,400 ****
--- 397,442 ----
  	return $self;
  }
  
+ package VC2012Project;
+ 
+ #
+ # Package that encapsulates a Visual C++ 2012 project file
+ #
+ 
+ use strict;
+ use warnings;
+ use base qw(MSBuildProject);
+ 
+ sub new
+ {
+     my $classname = shift;
+     my $self = $classname->SUPER::_new(@_);
+     bless($self, $classname);
+ 
+     $self->{vcver} = '11.00';
+ 
+     return $self;
+ }
+ 
+ # This override adds the <PlatformToolset> element
+ # to the PropertyGroup labeled "Configuration"
+ sub WriteConfigurationPropertyGroup
+ {
+     my ($self, $f, $cfgname, $p) = @_;
+     my $cfgtype =
+       ($self->{type} eq "exe")
+       ?'Application'
+       :($self->{type} eq "dll"?'DynamicLibrary':'StaticLibrary');
+ 
+     print $f <<EOF;
+   <PropertyGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'" Label="Configuration">
+     <ConfigurationType>$cfgtype</ConfigurationType>
+     <UseOfMfc>false</UseOfMfc>
+     <CharacterSet>MultiByte</CharacterSet>
+     <WholeProgramOptimization>$p->{wholeopt}</WholeProgramOptimization>
+     <PlatformToolset>v110</PlatformToolset>
+   </PropertyGroup>
+ EOF
+ }
+ 
  1;
diff --git a/src/tools/msvc/README b/src/tools/msvc/README
new file mode 100644
index 3b2939a..b61ddb8
*** a/src/tools/msvc/README
--- b/src/tools/msvc/README
*************** These configuration arguments are passed
*** 92,101 ****
  (Mkvcbuild.pm) which creates the Visual Studio project and solution files.
  It does this by using VSObjectFactory::CreateSolution to create an object
  implementing the Solution interface (this could be either a VS2005Solution,
! a VS2008Solution or a VS2010Solution, all in Solution.pm, depending on the
! user's build environment) and adding objects implementing the corresponding
! Project interface (VC2005Project or VC2008Project from VCBuildProject.pm or
! VC2010Project from MSBuildProject.pm) to it.
  When Solution::Save is called, the implementations of Solution and Project
  save their content in the appropriate format.
  The final step of starting the appropriate build program (msbuild or vcbuild)
--- 92,102 ----
  (Mkvcbuild.pm) which creates the Visual Studio project and solution files.
  It does this by using VSObjectFactory::CreateSolution to create an object
  implementing the Solution interface (this could be either a VS2005Solution,
! a VS2008Solution, a VS2010Solution or a VS2012Solution, all in Solution.pm,
! depending on the user's build environment) and adding objects implementing
! the corresponding Project interface (VC2005Project or VC2008Project from
! VCBuildProject.pm or VC2010Project or VC2012Project from MSBuildProject.pm)
! to it.
  When Solution::Save is called, the implementations of Solution and Project
  save their content in the appropriate format.
  The final step of starting the appropriate build program (msbuild or vcbuild)
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
new file mode 100644
index 850a1df..e271ac8
*** a/src/tools/msvc/Solution.pm
--- b/src/tools/msvc/Solution.pm
*************** sub DeterminePlatform
*** 63,75 ****
  {
  	my $self = shift;
  
! 	# Determine if we are in 32 or 64-bit mode. Do this by seeing if CL has
! 	# 64-bit only parameters.
  	$self->{platform} = 'Win32';
! 	open(P, "cl /? 2>NUL|") || die "cl command not found";
  	while (<P>)
  	{
! 		if (/^\/favor:</)
  		{
  			$self->{platform} = 'x64';
  			last;
--- 63,74 ----
  {
  	my $self = shift;
  
! 	# Examine CL help output to determine if we are in 32 or 64-bit mode.
  	$self->{platform} = 'Win32';
! 	open(P, "cl /? 2>&1 |") || die "cl command not found";
  	while (<P>)
  	{
! 		if (/^\/favor:<.+AMD64/)
  		{
  			$self->{platform} = 'x64';
  			last;
*************** sub new
*** 700,703 ****
--- 699,726 ----
  	return $self;
  }
  
+ package VS2012Solution;
+ 
+ #
+ # Package that encapsulates a Visual Studio 2012 solution file
+ #
+ 
+ use Carp;
+ use strict;
+ use warnings;
+ use base qw(Solution);
+ 
+ sub new
+ {
+     my $classname = shift;
+     my $self = $classname->SUPER::_new(@_);
+     bless($self, $classname);
+ 
+     $self->{solutionFileVersion} = '12.00';
+     $self->{vcver} = '11.00';
+     $self->{visualStudioName} = 'Visual Studio 2012';
+ 
+     return $self;
+ }
+ 
  1;
diff --git a/src/tools/msvc/VSObjectFactory.pm b/src/tools/msvc/VSObjectFactory.pm
new file mode 100644
index c3aa33e..0fbf3fa
*** a/src/tools/msvc/VSObjectFactory.pm
--- b/src/tools/msvc/VSObjectFactory.pm
*************** sub CreateSolution
*** 41,46 ****
--- 41,50 ----
  	{
  		return new VS2010Solution(@_);
  	}
+ 	elsif ($visualStudioVersion eq '11.00')
+ 	{
+ 		return new VS2012Solution(@_);
+ 	}
  	else
  	{
  		croak "The requested Visual Studio version is not supported.";
*************** sub CreateProject
*** 68,73 ****
--- 72,81 ----
  	{
  		return new VC2010Project(@_);
  	}
+ 	elsif ($visualStudioVersion eq '11.00')
+ 	{
+ 		return new VC2012Project(@_);
+ 	}
  	else
  	{
  		croak "The requested Visual Studio version is not supported.";
*************** sub DetermineVisualStudioVersion
*** 82,88 ****
  	{
  
  # Determine version of nmake command, to set proper version of visual studio
! # we use nmake as it has existed for a long time and still exists in visual studio 2010
  		open(P, "nmake /? 2>&1 |")
  		  || croak
  "Unable to determine Visual Studio version: The nmake command wasn't found.";
--- 90,96 ----
  	{
  
  # Determine version of nmake command, to set proper version of visual studio
! # we use nmake as it has existed for a long time and still exists in current visual studio versions
  		open(P, "nmake /? 2>&1 |")
  		  || croak
  "Unable to determine Visual Studio version: The nmake command wasn't found.";
*************** sub DetermineVisualStudioVersion
*** 107,117 ****
  sub _GetVisualStudioVersion
  {
  	my ($major, $minor) = @_;
! 	if ($major > 10)
  	{
  		carp
  "The determined version of Visual Studio is newer than the latest supported version. Returning the latest supported version instead.";
! 		return '10.00';
  	}
  	elsif ($major < 6)
  	{
--- 115,125 ----
  sub _GetVisualStudioVersion
  {
  	my ($major, $minor) = @_;
! 	if ($major > 11)
  	{
  		carp
  "The determined version of Visual Studio is newer than the latest supported version. Returning the latest supported version instead.";
! 		return '11.00';
  	}
  	elsif ($major < 6)
  	{
diff --git a/src/tools/msvc/build.pl b/src/tools/msvc/build.pl
new file mode 100644
index 8979402..c947bbe
*** a/src/tools/msvc/build.pl
--- b/src/tools/msvc/build.pl
*************** elsif ($ARGV[0] ne "RELEASE")
*** 50,56 ****
  
  # ... and do it
  
! if ($buildwhat and $vcver eq '10.00')
  {
  	system(
  "msbuild $buildwhat.vcxproj /verbosity:detailed /p:Configuration=$bconf");
--- 50,56 ----
  
  # ... and do it
  
! if ($buildwhat and $vcver >= 10.00)
  {
  	system(
  "msbuild $buildwhat.vcxproj /verbosity:detailed /p:Configuration=$bconf");
diff --git a/src/tools/msvc/gendef.pl b/src/tools/msvc/gendef.pl
new file mode 100644
index ab65c46..8ef0422
*** a/src/tools/msvc/gendef.pl
--- b/src/tools/msvc/gendef.pl
*************** while (<$ARGV[0]/*.obj>)
*** 40,45 ****
--- 40,46 ----
  		next if $pieces[6] =~ /^\(/;
  		next if $pieces[6] =~ /^__real/;
  		next if $pieces[6] =~ /^__imp/;
+ 		next if $pieces[6] =~ /^__xmm/;
  		next if $pieces[6] =~ /NULL_THUNK_DATA$/;
  		next if $pieces[6] =~ /^__IMPORT_DESCRIPTOR/;
  		next if $pieces[6] =~ /^__NULL_IMPORT/;
-- 
1.7.11.7

