From e1c1e2173248f39c1b15fca7b2a31ad7b5199ce7 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Wed, 6 Feb 2013 14:52:29 -0500 Subject: [PATCH] Enable building with Microsoft Visual Studio 2012. Backpatch to release 9.2 Brar Piening and Noah Misch, reviewed by Craig Ringer. --- doc/src/sgml/install-windows.sgml | 22 ++++++---- 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, 213 insertions(+), 39 deletions(-) diff --git a/doc/src/sgml/install-windows.sgml b/doc/src/sgml/install-windows.sgml index 452cf3195a..a330381954 100644 --- a/doc/src/sgml/install-windows.sgml +++ b/doc/src/sgml/install-windows.sgml @@ -19,8 +19,8 @@ There are several different ways of building PostgreSQL on Windows. The simplest way to build with - Microsoft tools is to install a supported version of the - Microsoft Windows SDK and use the included + Microsoft tools is to install Visual Studio Express 2012 + for Windows Desktop and use the included compiler. It is also possible to build with the full Microsoft Visual C++ 2005, 2008 or 2010. In some cases that requires the installation of the Windows SDK @@ -77,17 +77,18 @@ Visual Studio Express or some versions of the Microsoft Windows SDK. If you do not already have a Visual Studio environment set up, the easiest - way is to use the compilers in the Windows SDK, - which is a free download from Microsoft. + ways are to use the compilers in the Windows SDK 7.1 + or those from Visual Studio Express 2012 for Windows + Desktop, which are both free downloads from Microsoft. PostgreSQL is known to support compilation using the compilers shipped with Visual Studio 2005 to - Visual Studio 2010 (including Express editions), + Visual Studio 2012 (including Express editions), as well as standalone Windows SDK releases 6.0 to 7.1. 64-bit PostgreSQL builds are only supported with - Microsoft Windows SDK version 6.0a and above or + Microsoft Windows SDK version 6.0a to 7.1 or Visual Studio 2008 and above. @@ -149,17 +150,20 @@ $ENV{PATH}=$ENV{PATH} . ';c:\some\where\bison\bin'; Microsoft Windows SDK - It is recommended that you upgrade to the latest supported version - of the Microsoft Windows SDK (currently + If your build environment doesn't ship with a supported version of the + Microsoft Windows SDK it + is recommended that you upgrade to the latest version (currently version 7.1), available for download from . You must always include the Windows Headers and Libraries part of the SDK. - If you install the Windows SDK + If you install a Windows SDK including the Visual C++ Compilers, you don't need Visual Studio to build. + Note that as of Version 8.0a the Windows SDK no longer ships with a + complete command-line build environment. diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 8fe824b426..890aa19816 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -715,12 +715,41 @@ cache_locale_time(void) #if defined(WIN32) && defined(LC_MESSAGES) /* - * Convert Windows locale name to the ISO formatted one - * if possible. + * Convert a Windows setlocale() argument to a Unix-style one. * - * This function returns NULL if conversion is impossible, - * otherwise returns the pointer to a static area which - * contains the iso formatted locale name. + * 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 [_][.], + * 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) @@ -739,6 +768,34 @@ IsoLocaleName(const char *winlocname) 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; @@ -753,6 +810,7 @@ IsoLocaleName(const char *winlocname) 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 index 1bba4268a5..b75d976856 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -935,14 +935,22 @@ find_matching_ts_config(const char *lc_type) /* * Convert lc_ctype to a language name by stripping everything after an - * underscore. Just for paranoia, we also stop at '.' or '@'. + * 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 != '@') + while (*ptr && + *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@') ptr++; *ptr = '\0'; } diff --git a/src/port/chklocale.c b/src/port/chklocale.c index 7e2062c6bb..9e889383f2 100644 --- a/src/port/chklocale.c +++ b/src/port/chklocale.c @@ -189,26 +189,49 @@ static const struct encoding_match encoding_match_list[] = { #ifdef WIN32 /* - * On Windows, use CP instead of the nl_langinfo() result + * On Windows, use CP 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; + 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; - int ln; /* * Locale format on Win32 is _. . For - * example, English_USA.1252. + * example, English_United States.1252. */ codepage = strrchr(ctype, '.'); - if (!codepage) - return NULL; - codepage++; - ln = strlen(codepage); - r = malloc(ln + 3); - sprintf(r, "CP%s", codepage); + 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 index 5f0f6f9859..b5f4e8e6d6 100644 --- a/src/port/win32env.c +++ b/src/port/win32env.c @@ -60,6 +60,12 @@ pgwin32_putenv(const char *envval) { "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 index 2e3eab6599..0cafd717a2 100644 --- a/src/tools/msvc/MSBuildProject.pm +++ b/src/tools/msvc/MSBuildProject.pm @@ -1,7 +1,7 @@ package MSBuildProject; # -# Package that encapsulates a MSBuild (Visual C++ 2010) project file +# Package that encapsulates a MSBuild project file (Visual C++ 2010 or greater) # # src/tools/msvc/MSBuildProject.pm # @@ -397,4 +397,46 @@ sub new 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 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 < + $cfgtype + false + MultiByte + $p->{wholeopt} + v110 + +EOF +} + 1; diff --git a/src/tools/msvc/README b/src/tools/msvc/README index 3b2939ad68..b61ddb8791 100644 --- a/src/tools/msvc/README +++ b/src/tools/msvc/README @@ -92,10 +92,11 @@ These configuration arguments are passed over to Mkvcbuild::mkvcbuild (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. +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 index 850a1dfabc..e271ac8d9b 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -63,13 +63,12 @@ sub DeterminePlatform { my $self = shift; - # Determine if we are in 32 or 64-bit mode. Do this by seeing if CL has - # 64-bit only parameters. + # Examine CL help output to determine if we are in 32 or 64-bit mode. $self->{platform} = 'Win32'; - open(P, "cl /? 2>NUL|") || die "cl command not found"; + open(P, "cl /? 2>&1 |") || die "cl command not found"; while (

) { - if (/^\/favor:{platform} = 'x64'; last; @@ -700,4 +699,28 @@ sub new 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 index c3aa33ec24..0fbf3faa0e 100644 --- a/src/tools/msvc/VSObjectFactory.pm +++ b/src/tools/msvc/VSObjectFactory.pm @@ -41,6 +41,10 @@ sub CreateSolution { return new VS2010Solution(@_); } + elsif ($visualStudioVersion eq '11.00') + { + return new VS2012Solution(@_); + } else { croak "The requested Visual Studio version is not supported."; @@ -68,6 +72,10 @@ sub CreateProject { return new VC2010Project(@_); } + elsif ($visualStudioVersion eq '11.00') + { + return new VC2012Project(@_); + } else { croak "The requested Visual Studio version is not supported."; @@ -82,7 +90,7 @@ sub DetermineVisualStudioVersion { # 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 +# 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."; @@ -107,11 +115,11 @@ sub DetermineVisualStudioVersion sub _GetVisualStudioVersion { my ($major, $minor) = @_; - if ($major > 10) + if ($major > 11) { carp "The determined version of Visual Studio is newer than the latest supported version. Returning the latest supported version instead."; - return '10.00'; + return '11.00'; } elsif ($major < 6) { diff --git a/src/tools/msvc/build.pl b/src/tools/msvc/build.pl index 8979402d4c..c947bbe318 100644 --- a/src/tools/msvc/build.pl +++ b/src/tools/msvc/build.pl @@ -50,7 +50,7 @@ elsif ($ARGV[0] ne "RELEASE") # ... and do it -if ($buildwhat and $vcver eq '10.00') +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 index ab65c46cfa..8ef0422df9 100644 --- a/src/tools/msvc/gendef.pl +++ b/src/tools/msvc/gendef.pl @@ -40,6 +40,7 @@ while (<$ARGV[0]/*.obj>) 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/;