[PATCH] Windows x64 - Mailing list pgsql-hackers

From Tsutomu Yamada
Subject [PATCH] Windows x64
Date
Msg-id 54774.1259666756@srapc2360.sra.co.jp
Whole thread Raw
Responses Re: [PATCH] Windows x64  (Robert Haas <robertmhaas@gmail.com>)
Re: [PATCH] Windows x64 [repost]  (Tsutomu Yamada <tsutomu@sraoss.co.jp>)
List pgsql-hackers
Hello.

The following patches support Windows x64.

1) use intptr_t for Datum and pointer macros. (to support Windows LLP64)
   almost the same as that post before.
   http://archives.postgresql.org/pgsql-hackers/2009-06/threads.php#01364

2) use appropriate macro and datatypes for Windows API.
   enables more than 32bits shared memory.

3) Build scripts for MSVC, this came from
   http://archives.postgresql.org/pgsql-hackers/2008-07/msg00440.php
   add new parameters to config.pl.
   You need define "platform" to "x64" for 64bit programs.

-----

Windows x64 binary that applied patch and build with MSVS2005 can pass
all regression tests (vcregress.bat).

I was checked where the string converted with "%ld" is used.
An especially fatal part is not found excluding one of plperl.

But there is still a possibility that elog messages output a incorrect value.
(I thought it is not fatal, ignored these for the present.)

(eg) src/backend/port/win32_shmem.c, line 167
     'size' is 'size_t' = 64bit value.
| ereport(FATAL,
|  (errmsg("could not create shared memory segment: %lu", GetLastError()),
|   errdetail("Failed system call was CreateFileMapping(size=%lu, name=%s).",
|             (unsigned long) size, szShareMem)));

The code that becomes a problem of plperl is the following.
The address is converted into the string, and it is used as hash key.

However, there is really little possibility that two address values
become the same low word, and the problem will not occur.
(Of course, it is necessary to fix though the problem doesn't occur.)


--- src/pl/plperl/plperl.c      2009-11-30 18:56:30.000000000 +0900
+++ /tmp/plperl.c       2009-12-01 18:46:43.000000000 +0900
@@ -95,7 +95,7 @@
  **********************************************************************/
 typedef struct plperl_query_desc
 {
-       char            qname[sizeof(long) * 2 + 1];
+       char            qname[sizeof(void *) * 2 + 1];
        void       *plan;
        int                     nargs;
        Oid                *argtypes;
@@ -2343,7 +2343,8 @@
         ************************************************************/
        qdesc = (plperl_query_desc *) malloc(sizeof(plperl_query_desc));
        MemSet(qdesc, 0, sizeof(plperl_query_desc));
-       snprintf(qdesc->qname, sizeof(qdesc->qname), "%lx", (long) qdesc);
+       /* XXX: for LLP64, use %p or %ll */
+       snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
        qdesc->nargs = argc;
        qdesc->argtypes = (Oid *) malloc(argc * sizeof(Oid));
        qdesc->arginfuncs = (FmgrInfo *) malloc(argc * sizeof(FmgrInfo));

--
Tsutomu Yamada
SRA OSS, Inc. Japan

>From b6e51007eb3bfb9dd4333dfa1bfd479a049d70f0 Mon Sep 17 00:00:00 2001
From: Tsutomu Yamada <tsutomu@sraoss.co.jp>
Date: Wed, 26 Aug 2009 21:39:32 +0900
Subject: [PATCH 1/3] use uintptr_t for Datum

fix typedef, and pointer arithmetics.
for LLP64 (Windows x64)
---
 src/backend/access/common/heaptuple.c |    6 +++---
 src/backend/access/hash/hashfunc.c    |    2 +-
 src/backend/storage/lmgr/lwlock.c     |    2 +-
 src/include/access/tupmacs.h          |    2 +-
 src/include/c.h                       |   11 +++++++----
 src/include/pg_config.h.win32         |    7 +++++++
 src/include/postgres.h                |    4 ++--
 src/interfaces/ecpg/ecpglib/data.c    |    8 ++++----
 8 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index a86716e..f429f68 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -192,7 +192,7 @@ heap_fill_tuple(TupleDesc tupleDesc,
         if (att[i]->attbyval)
         {
             /* pass-by-value */
-            data = (char *) att_align_nominal((long) data, att[i]->attalign);
+            data = (char *) att_align_nominal(data, att[i]->attalign);
             store_att_byval(data, values[i], att[i]->attlen);
             data_length = att[i]->attlen;
         }
@@ -226,7 +226,7 @@ heap_fill_tuple(TupleDesc tupleDesc,
             else
             {
                 /* full 4-byte header varlena */
-                data = (char *) att_align_nominal((long) data,
+                data = (char *) att_align_nominal(data,
                                                   att[i]->attalign);
                 data_length = VARSIZE(val);
                 memcpy(data, val, data_length);
@@ -243,7 +243,7 @@ heap_fill_tuple(TupleDesc tupleDesc,
         else
         {
             /* fixed-length pass-by-reference */
-            data = (char *) att_align_nominal((long) data, att[i]->attalign);
+            data = (char *) att_align_nominal(data, att[i]->attalign);
             Assert(att[i]->attlen > 0);
             data_length = att[i]->attlen;
             memcpy(data, DatumGetPointer(values[i]), data_length);
diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c
index a38103e..d3efb29 100644
--- a/src/backend/access/hash/hashfunc.c
+++ b/src/backend/access/hash/hashfunc.c
@@ -319,7 +319,7 @@ hash_any(register const unsigned char *k, register int keylen)
     a = b = c = 0x9e3779b9 + len + 3923095;

     /* If the source pointer is word-aligned, we use word-wide fetches */
-    if (((long) k & UINT32_ALIGN_MASK) == 0)
+    if (((intptr_t) k & UINT32_ALIGN_MASK) == 0)
     {
         /* Code path for aligned source data */
         register const uint32 *ka = (const uint32 *) k;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index f2ccbe1..5d88b02 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -245,7 +245,7 @@ CreateLWLocks(void)
     ptr += 2 * sizeof(int);

     /* Ensure desired alignment of LWLock array */
-    ptr += LWLOCK_PADDED_SIZE - ((unsigned long) ptr) % LWLOCK_PADDED_SIZE;
+    ptr += LWLOCK_PADDED_SIZE - ((uintptr_t) ptr) % LWLOCK_PADDED_SIZE;

     LWLockArray = (LWLockPadded *) ptr;

diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index 7666aaa..82ee422 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -142,7 +142,7 @@
 #define att_align_nominal(cur_offset, attalign) \
 ( \
     ((attalign) == 'i') ? INTALIGN(cur_offset) : \
-     (((attalign) == 'c') ? (long) (cur_offset) : \
+     (((attalign) == 'c') ? (intptr_t) (cur_offset) : \
       (((attalign) == 'd') ? DOUBLEALIGN(cur_offset) : \
        ( \
             AssertMacro((attalign) == 's'), \
diff --git a/src/include/c.h b/src/include/c.h
index 44efac4..acaec39 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -72,6 +72,9 @@
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
 #include <sys/types.h>

 #include <errno.h>
@@ -492,7 +495,7 @@ typedef NameData *Name;
  *        True iff pointer is properly aligned to point to the given type.
  */
 #define PointerIsAligned(pointer, type) \
-        (((long)(pointer) % (sizeof (type))) == 0)
+        (((intptr_t)(pointer) % (sizeof (type))) == 0)

 #define OidIsValid(objectId)  ((bool) ((objectId) != InvalidOid))

@@ -538,7 +541,7 @@ typedef NameData *Name;
  */

 #define TYPEALIGN(ALIGNVAL,LEN)  \
-    (((long) (LEN) + ((ALIGNVAL) - 1)) & ~((long) ((ALIGNVAL) - 1)))
+    (((intptr_t) (LEN) + ((ALIGNVAL) - 1)) & ~((intptr_t) ((ALIGNVAL) - 1)))

 #define SHORTALIGN(LEN)            TYPEALIGN(ALIGNOF_SHORT, (LEN))
 #define INTALIGN(LEN)            TYPEALIGN(ALIGNOF_INT, (LEN))
@@ -549,7 +552,7 @@ typedef NameData *Name;
 #define BUFFERALIGN(LEN)        TYPEALIGN(ALIGNOF_BUFFER, (LEN))

 #define TYPEALIGN_DOWN(ALIGNVAL,LEN)  \
-    (((long) (LEN)) & ~((long) ((ALIGNVAL) - 1)))
+    (((intptr_t) (LEN)) & ~((intptr_t) ((ALIGNVAL) - 1)))

 #define SHORTALIGN_DOWN(LEN)    TYPEALIGN_DOWN(ALIGNOF_SHORT, (LEN))
 #define INTALIGN_DOWN(LEN)        TYPEALIGN_DOWN(ALIGNOF_INT, (LEN))
@@ -630,7 +633,7 @@ typedef NameData *Name;
         int        _val = (val); \
         Size    _len = (len); \
 \
-        if ((((long) _vstart) & LONG_ALIGN_MASK) == 0 && \
+        if ((((intptr_t) _vstart) & LONG_ALIGN_MASK) == 0 && \
             (_len & LONG_ALIGN_MASK) == 0 && \
             _val == 0 && \
             _len <= MEMSET_LOOP_LIMIT && \
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index a3b3b73..b1981fd 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -347,7 +347,11 @@
 /* #undef HAVE_SRANDOM */

 /* Define to 1 if you have the <stdint.h> header file. */
+#ifdef _MSC_VER
+/* #undef HAVE_STDINT_H */
+#else
 #define HAVE_STDINT_H 1
+#endif

 /* Define to 1 if you have the <stdlib.h> header file. */
 #define HAVE_STDLIB_H 1
@@ -591,6 +595,9 @@
 /* The size of a `unsigned long', as computed by sizeof. */
 #define SIZEOF_UNSIGNED_LONG 4

+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 4
+
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1

diff --git a/src/include/postgres.h b/src/include/postgres.h
index 26dfecc..e0d04c1 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -305,9 +305,9 @@ typedef struct
  * or short may contain garbage when called as if it returned Datum.
  */

-typedef unsigned long Datum;    /* XXX sizeof(long) >= sizeof(void *) */
+typedef uintptr_t Datum;        /* XXX sizeof(long) >= sizeof(void *) */

-#define SIZEOF_DATUM SIZEOF_UNSIGNED_LONG
+#define SIZEOF_DATUM SIZEOF_VOID_P

 typedef Datum *DatumPtr;

diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c
index d468de6..12ee7a8 100644
--- a/src/interfaces/ecpg/ecpglib/data.c
+++ b/src/interfaces/ecpg/ecpglib/data.c
@@ -162,11 +162,11 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
         if (binary)
         {
             if (varcharsize == 0 || varcharsize * offset >= size)
-                memcpy((char *) ((long) var + offset * act_tuple),
+                memcpy((char *) (var + offset * act_tuple),
                        pval, size);
             else
             {
-                memcpy((char *) ((long) var + offset * act_tuple),
+                memcpy((char *) (var + offset * act_tuple),
                        pval, varcharsize * offset);

                 if (varcharsize * offset < size)
@@ -371,7 +371,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                 case ECPGt_unsigned_char:
                 case ECPGt_string:
                     {
-                        char    *str = (char *) ((long) var + offset * act_tuple);
+                        char    *str = (char *) (var + offset * act_tuple);
                         if (varcharsize == 0 || varcharsize > size)
                         {
                             strncpy(str, pval, size + 1);
@@ -426,7 +426,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                 case ECPGt_varchar:
                     {
                         struct ECPGgeneric_varchar *variable =
-                        (struct ECPGgeneric_varchar *) ((long) var + offset * act_tuple);
+                        (struct ECPGgeneric_varchar *) (var + offset * act_tuple);

                         variable->len = size;
                         if (varcharsize == 0)
--
1.6.4

>From 965ac3c8142a5b8afdd7410f930c23fa9d5657a9 Mon Sep 17 00:00:00 2001
From: Tsutomu Yamada <tsutomu@sraoss.co.jp>
Date: Fri, 28 Aug 2009 18:39:49 +0900
Subject: [PATCH 2/3] fix for Windows x64

* add defines for WIN64
* support over 4GB shared memory
* fix API portablity
---
 src/backend/port/win32_shmem.c      |   29 +++++++++++++++++++----------
 src/backend/postmaster/postmaster.c |    4 ++++
 src/backend/postmaster/syslogger.c  |    2 +-
 src/include/pg_config.h.win32       |    8 ++++++++
 src/include/storage/pg_shmem.h      |    4 ++++
 src/include/storage/s_lock.h        |   12 ++++++++++++
 src/port/open.c                     |    2 +-
 7 files changed, 49 insertions(+), 12 deletions(-)

diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index fc8e51b..6a31b1c 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -16,7 +16,7 @@
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"

-unsigned long UsedShmemSegID = 0;
+HANDLE        UsedShmemSegID = 0;
 void       *UsedShmemSegAddr = NULL;
 static Size UsedShmemSegSize = 0;

@@ -125,6 +125,8 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
                 hmap2;
     char       *szShareMem;
     int            i;
+    DWORD        size_high;
+    DWORD        size_low;

     /* Room for a header? */
     Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
@@ -133,6 +135,13 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)

     UsedShmemSegAddr = NULL;

+#ifdef _WIN64
+    size_high = size >> 32;
+#else
+    size_high = 0;
+#endif
+    size_low = (DWORD) size;
+
     /*
      * When recycling a shared memory segment, it may take a short while
      * before it gets dropped from the global namespace. So re-try after
@@ -147,11 +156,11 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
          */
         SetLastError(0);

-        hmap = CreateFileMapping((HANDLE) 0xFFFFFFFF,    /* Use the pagefile */
+        hmap = CreateFileMapping(INVALID_HANDLE_VALUE,    /* Use the pagefile */
                                  NULL,    /* Default security attrs */
                                  PAGE_READWRITE,        /* Memory is Read/Write */
-                                 0L,    /* Size Upper 32 Bits    */
-                                 (DWORD) size,    /* Size Lower 32 bits */
+                                 size_high,    /* Size Upper 32 Bits    */
+                                 size_low,    /* Size Lower 32 bits */
                                  szShareMem);

         if (!hmap)
@@ -203,7 +212,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)


     /* Register on-exit routine to delete the new segment */
-    on_shmem_exit(pgwin32_SharedMemoryDelete, Int32GetDatum((unsigned long) hmap2));
+    on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));

     /*
      * Get a pointer to the new shared memory segment. Map the whole segment
@@ -235,7 +244,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
     /* Save info for possible future use */
     UsedShmemSegAddr = memAddress;
     UsedShmemSegSize = size;
-    UsedShmemSegID = (unsigned long) hmap2;
+    UsedShmemSegID = hmap2;

     return hdr;
 }
@@ -266,10 +275,10 @@ PGSharedMemoryReAttach(void)
         elog(FATAL, "failed to release reserved memory region (addr=%p): %lu",
              UsedShmemSegAddr, GetLastError());

-    hdr = (PGShmemHeader *) MapViewOfFileEx((HANDLE) UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0,
UsedShmemSegAddr);
+    hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0,
UsedShmemSegAddr);
     if (!hdr)
-        elog(FATAL, "could not reattach to shared memory (key=%d, addr=%p): %lu",
-             (int) UsedShmemSegID, UsedShmemSegAddr, GetLastError());
+        elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): %lu",
+             UsedShmemSegID, UsedShmemSegAddr, GetLastError());
     if (hdr != origUsedShmemSegAddr)
         elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
              hdr, origUsedShmemSegAddr);
@@ -308,7 +317,7 @@ static void
 pgwin32_SharedMemoryDelete(int status, Datum shmId)
 {
     PGSharedMemoryDetach();
-    if (!CloseHandle((HANDLE) DatumGetInt32(shmId)))
+    if (!CloseHandle(DatumGetPointer(shmId)))
         elog(LOG, "could not close handle to shared memory: %lu", GetLastError());
 }

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e94181a..d1e52d1 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -402,7 +402,11 @@ typedef struct
     int            ListenSocket[MAXLISTEN];
     long        MyCancelKey;
     int            MyPMChildSlot;
+#ifndef WIN32
     unsigned long UsedShmemSegID;
+#else
+     HANDLE        UsedShmemSegID;
+#endif
     void       *UsedShmemSegAddr;
     slock_t    *ShmemLock;
     VariableCache ShmemVariableCache;
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 96865e1..ebc4388 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -573,7 +573,7 @@ SysLogger_Start(void)
                  * chunking protocol.
                  */
                 fflush(stderr);
-                fd = _open_osfhandle((long) syslogPipe[1],
+                fd = _open_osfhandle((intptr_t) syslogPipe[1],
                                      _O_APPEND | _O_BINARY);
                 if (dup2(fd, _fileno(stderr)) < 0)
                     ereport(FATAL,
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index b1981fd..0621c15 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -590,13 +590,21 @@
 /* #undef PTHREAD_CREATE_JOINABLE */

 /* The size of a `size_t', as computed by sizeof. */
+#ifdef _WIN64
+#define SIZEOF_SIZE_T 8
+#else
 #define SIZEOF_SIZE_T 4
+#endif

 /* The size of a `unsigned long', as computed by sizeof. */
 #define SIZEOF_UNSIGNED_LONG 4

 /* The size of `void *', as computed by sizeof. */
+#ifdef _WIN64
+#define SIZEOF_VOID_P 8
+#else
 #define SIZEOF_VOID_P 4
+#endif

 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index 37fae22..bc23c1d 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -40,7 +40,11 @@ typedef struct PGShmemHeader    /* standard header for all Postgres shmem */


 #ifdef EXEC_BACKEND
+#ifndef WIN32
 extern unsigned long UsedShmemSegID;
+#else
+extern HANDLE UsedShmemSegID;
+#endif
 extern void *UsedShmemSegAddr;

 extern void PGSharedMemoryReAttach(void);
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 48208b9..74c6dd7 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -836,12 +836,24 @@ typedef LONG slock_t;

 #define SPIN_DELAY() spin_delay()

+/* If using Visual C 2005 or 2008 on Win64, inline assembly is unavailable.
+ * Use a __noop instrinsic instead of rep nop.
+ * Might be slightly less efficient on EMT64, but its the same for AMD.
+ */
+#if defined(_WIN64) && defined(_MSC_VER) && (_MSC_VER == 1400 || _MSC_VER == 1500)
+static __forceinline void
+spin_delay(void)
+{
+    __noop();
+}
+#else
 static __forceinline void
 spin_delay(void)
 {
     /* See comment for gcc code. Same code, MASM syntax */
     __asm rep nop;
 }
+#endif

 #endif

diff --git a/src/port/open.c b/src/port/open.c
index f3a0a15..74edc99 100644
--- a/src/port/open.c
+++ b/src/port/open.c
@@ -124,7 +124,7 @@ pgwin32_open(const char *fileName, int fileFlags,...)
     }

     /* _open_osfhandle will, on error, set errno accordingly */
-    if ((fd = _open_osfhandle((long) h, fileFlags & O_APPEND)) < 0)
+    if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
         CloseHandle(h);            /* will not affect errno */
     else if (fileFlags & (O_TEXT | O_BINARY) &&
              _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
--
1.6.4

>From 2720f373369f2230567e192b6ce6b10d5e6ad304 Mon Sep 17 00:00:00 2001
From: Tsutomu Yamada <tsutomu@sraoss.co.jp>
Date: Fri, 28 Aug 2009 19:35:38 +0900
Subject: [PATCH 3/3] MSVC build scripts for Windows x64

* add platform x64
* support VC2008
---
 src/tools/msvc/Mkvcbuild.pm |   14 ++++++++
 src/tools/msvc/Project.pm   |   75 +++++++++++++++++++++++++++++++++---------
 src/tools/msvc/Solution.pm  |   20 +++++++----
 src/tools/msvc/clean.bat    |    5 +++
 src/tools/msvc/config.pl    |    5 +++
 src/tools/msvc/gendef.pl    |   29 +++++++++++-----
 6 files changed, 115 insertions(+), 33 deletions(-)

diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 9b5d149..1264524 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -387,6 +387,20 @@ sub mkvcbuild
     $pgregress->AddReference($libpgport);

     $solution->Save();
+
+    # If this is Studio 2008 and up, then the projects need up be upgraded first
+    if ($config->{msvc_version} ge 1500)
+    {
+    print "Converting projects to current Visual Studio version...\n";
+    foreach my $fld (keys %{$solution->{projects}})
+    {
+        foreach my $proj (@{$solution->{projects}->{$fld}})
+        {
+        print "\n\nUpgrading $proj->{name}\n\n";
+        system("vcbuild /upgrade $proj->{name}.vcproj");
+        }
+    }
+    }
 }

 #####################
diff --git a/src/tools/msvc/Project.pm b/src/tools/msvc/Project.pm
index 4118011..415fdd1 100644
--- a/src/tools/msvc/Project.pm
+++ b/src/tools/msvc/Project.pm
@@ -338,6 +338,7 @@ sub DisableLinkerWarnings
 sub Save
 {
     my ($self) = @_;
+    my $platform = $self->{solution}->{options}->{platform};

     # If doing DLL and haven't specified a DEF file, do a full export of all symbols
     # in the project.
@@ -391,7 +392,7 @@ EOF
             $of =~ s{^src\\pl\\plpgsql\\src\\gram.c$}{src\\pl\\plpgsql\\src\\pl_gram.c};
             print F '>'
               . GenerateCustomTool('Running bison on ' . $f,
-                'cmd /V:ON /c src\tools\msvc\pgbison.bat ' . $f, $of)
+                'cmd /V:ON /c src\tools\msvc\pgbison.bat ' . $f, $of, $platform)
               . '</File>' . "\n";
         }
         elsif ($f =~ /\.l$/)
@@ -399,7 +400,7 @@ EOF
             my $of = $f;
             $of =~ s/\.l$/.c/;
             print F '>'
-              . GenerateCustomTool('Running flex on ' . $f, 'src\tools\msvc\pgflex.bat ' . $f,$of)
+              . GenerateCustomTool('Running flex on ' . $f, 'src\tools\msvc\pgflex.bat ' . $f,$of, $platform)
               . '</File>' . "\n";
         }
         elsif (defined($uniquefiles{$file}))
@@ -409,8 +410,8 @@ EOF
             my $obj = $dir;
             $obj =~ s/\\/_/g;
             print F
-"><FileConfiguration Name=\"Debug|Win32\"><Tool Name=\"VCCLCompilerTool\" ObjectFile=\".\\debug\\$self->{name}\\$obj"
-              . "_$file.obj\" /></FileConfiguration><FileConfiguration Name=\"Release|Win32\"><Tool
Name=\"VCCLCompilerTool\"ObjectFile=\".\\release\\$self->{name}\\$obj" 
+"><FileConfiguration Name=\"Debug|$platform\"><Tool Name=\"VCCLCompilerTool\"
ObjectFile=\".\\debug\\$self->{name}\\$obj"
+              . "_$file.obj\" /></FileConfiguration><FileConfiguration Name=\"Release|$platform\"><Tool
Name=\"VCCLCompilerTool\"ObjectFile=\".\\release\\$self->{name}\\$obj" 
               . "_$file.obj\" /></FileConfiguration></File>\n";
         }
         else
@@ -430,14 +431,14 @@ EOF

 sub GenerateCustomTool
 {
-    my ($desc, $tool, $output, $cfg) = @_;
+    my ($desc, $tool, $output, $platform, $cfg) = @_;
     if (!defined($cfg))
     {
-        return GenerateCustomTool($desc, $tool, $output, 'Debug')
-          .GenerateCustomTool($desc, $tool, $output, 'Release');
+        return GenerateCustomTool($desc, $tool, $output, $platform, 'Debug')
+          .GenerateCustomTool($desc, $tool, $output, $platform, 'Release');
     }
     return
-"<FileConfiguration Name=\"$cfg|Win32\"><Tool Name=\"VCCustomBuildTool\" Description=\"$desc\" CommandLine=\"$tool\"
AdditionalDependencies=\"\"Outputs=\"$output\" /></FileConfiguration>"; 
+"<FileConfiguration Name=\"$cfg|$platform\"><Tool Name=\"VCCustomBuildTool\" Description=\"$desc\"
CommandLine=\"$tool\"AdditionalDependencies=\"\" Outputs=\"$output\" /></FileConfiguration>"; 
 }

 sub WriteReferences
@@ -455,11 +456,12 @@ sub WriteReferences
 sub WriteHeader
 {
     my ($self, $f) = @_;
+    my $platform = $self->{solution}->{options}->{platform};

     print $f <<EOF;
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject ProjectType="Visual C++" Version="8.00" Name="$self->{name}" ProjectGUID="$self->{guid}">
- <Platforms><Platform Name="Win32"/></Platforms>
+ <Platforms><Platform Name="$platform"/></Platforms>
  <Configurations>
 EOF
     $self->WriteConfiguration($f, 'Debug',
@@ -477,6 +479,47 @@ sub WriteConfiguration
     my $cfgtype = ($self->{type} eq "exe")?1:($self->{type} eq "dll"?2:4);
     my $libcfg = (uc $cfgname eq "RELEASE")?"MD":"MDd";
     my $libs = '';
+    my $platform = $self->{solution}->{options}->{platform};
+    my $local_compiler_opt = $self->{solution}->{options}->{compiler_opt};
+    my $local_linker_opt = $self->{solution}->{options}->{linker_opt};
+
+    # Enable to use of multiple CPUs/cores
+    $local_compiler_opt .= ' ' unless ($local_compiler_opt eq '');
+    $local_compiler_opt .= ' /MP';
+
+    # We should specify the target machine as an additional option, since Microsoft uses cryptic
+    # undocumented codes for different target platforms.
+    $local_linker_opt .= ' ' unless ($local_linker_opt eq ''); # add a space
+    if ($platform eq 'Win32')
+    {
+        $local_linker_opt .= '/Machine:X86';
+    }
+    elsif ($platform eq 'x64')
+    {
+        $local_linker_opt .= '/Machine:X64';
+    }
+    else
+    {
+        die 'That platform is not supported';
+    }
+
+    # if we're using x64, we need to disable LNK4197.  This link explains why:
+    # http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99193
+    if ($platform eq 'x64')
+    {
+        # from some reason (?) it is an error to specify this together with the other /ignore arguments...
+        # making it separate makes the error disappear
+        $local_linker_opt .= ' ' unless ($local_linker_opt eq ''); # add a space
+        $local_linker_opt .= '/ignore:4197';
+    }
+
+    # Fold the disable linker warnings stuff into the local_linker_opt variable
+    if ($self->{disablelinkerwarnings})
+    {
+        $local_linker_opt .= ' ' unless ($local_linker_opt eq ''); # add a space
+        $local_linker_opt .= "/ignore:$self->{disablelinkerwarnings}";
+    }
+
     foreach my $lib (@{$self->{libraries}})
     {
         my $xlib = $lib;
@@ -493,20 +536,21 @@ sub WriteConfiguration
     $libs =~ s/ $//;
     $libs =~ s/__CFGNAME__/$cfgname/g;
     print $f <<EOF;
-  <Configuration Name="$cfgname|Win32" OutputDirectory=".\\$cfgname\\$self->{name}"
IntermediateDirectory=".\\$cfgname\\$self->{name}"
+  <Configuration Name="$cfgname|$platform" OutputDirectory=".\\$cfgname\\$self->{name}"
IntermediateDirectory=".\\$cfgname\\$self->{name}"
     ConfigurationType="$cfgtype" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE" CharacterSet="2"
WholeProgramOptimization="$p->{wholeopt}">
     <Tool Name="VCCLCompilerTool" Optimization="$p->{opt}"
+        AdditionalOptions="$local_compiler_opt"

AdditionalIncludeDirectories="$self->{prefixincludes}src/include;src/include/port/win32;src/include/port/win32_msvc;$self->{includes}"

PreprocessorDefinitions="WIN32;_WINDOWS;__WINDOWS__;__WIN32__;EXEC_BACKEND;WIN32_STACK_RLIMIT=4194304;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}$p->{defs}"
         StringPooling="$p->{strpool}"
         RuntimeLibrary="$p->{runtime}" DisableSpecificWarnings="$self->{disablewarnings}"
-        AdditionalOptions="/MP"
 EOF
     print $f <<EOF;
         AssemblerOutput="0" AssemblerListingLocation=".\\$cfgname\\$self->{name}\\"
ObjectFile=".\\$cfgname\\$self->{name}\\"
         ProgramDataBaseFileName=".\\$cfgname\\$self->{name}\\" BrowseInformation="0"
         WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/>
     <Tool Name="VCLinkerTool" OutputFile=".\\$cfgname\\$self->{name}\\$self->{name}.$self->{type}"
+        AdditionalOptions="$local_linker_opt"
         AdditionalDependencies="$libs"
         LinkIncremental="0" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories=""
IgnoreDefaultLibraryNames="libc"
         StackReserveSize="4194304" DisableSpecificWarnings="$self->{disablewarnings}"
@@ -514,10 +558,6 @@ EOF
         GenerateMapFile="FALSE" MapFileName=".\\$cfgname\\$self->{name}\\$self->{name}.map"
         SubSystem="1" TargetMachine="1"
 EOF
-    if ($self->{disablelinkerwarnings})
-    {
-        print $f "\t\tAdditionalOptions=\"/ignore:$self->{disablelinkerwarnings}\"\n";
-    }
     if ($self->{implib})
     {
         my $l = $self->{implib};
@@ -538,8 +578,11 @@ EOF
       "\t<Tool Name=\"VCResourceCompilerTool\" AdditionalIncludeDirectories=\"src\\include\" />\n";
     if ($self->{builddef})
     {
+        # gendef needs to be passed the platform now, because the x64 COFF ABI is different
+        # than the 32 bit ABI.  The old one placed a _ in front of all the symbols we need, while
+        # the x64 version has no special prefix
         print $f
-"\t<Tool Name=\"VCPreLinkEventTool\" Description=\"Generate DEF file\" CommandLine=\"perl src\\tools\\msvc\\gendef.pl
$cfgname\\$self->{name}\"/>\n"; 
+"\t<Tool Name=\"VCPreLinkEventTool\" Description=\"Generate DEF file\" CommandLine=\"perl src\\tools\\msvc\\gendef.pl
$cfgname\\$self->{name}$platform\" />\n"; 
     }
     print $f <<EOF;
   </Configuration>
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index d2621cb..80804ff 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -87,6 +87,10 @@ sub copyFile
 sub GenerateFiles
 {
     my $self = shift;
+    my $platform = $self->{options}->{platform};
+    my $bits = "unknown";
+    $bits = "32-bit" if ($platform eq 'Win32');
+    $bits = "64-bit" if ($platform eq 'x64');

     # Parse configure.in to get version numbers
     open(C,"configure.in") || confess("Could not open configure.in for reading\n");
@@ -122,8 +126,7 @@ sub GenerateFiles
         {
             s{PG_VERSION "[^"]+"}{PG_VERSION "$self->{strver}"};
             s{PG_VERSION_NUM \d+}{PG_VERSION_NUM $self->{numver}};
-            # XXX: When we support 64-bit, need to remove this hardcoding
-s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY(z)\n#define PG_VERSION_STR
"PostgreSQL$self->{strver}, compiled by Visual C++ build " __STRINGIFY2(_MSC_VER) ", 32-bit"}; 
+s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY(z)\n#define PG_VERSION_STR
"PostgreSQL$self->{strver}, compiled by Visual C++ build " __STRINGIFY2(_MSC_VER) ", $bits"}; 
             print O;
         }
         print O "#define PG_MAJORVERSION \"$self->{majorver}\"\n";
@@ -385,6 +388,7 @@ sub AddProject
 sub Save
 {
     my ($self) = @_;
+    my $platform = $self->{options}->{platform};
     my %flduid;

     $self->GenerateFiles();
@@ -424,8 +428,8 @@ EOF
     print SLN <<EOF;
 Global
     GlobalSection(SolutionConfigurationPlatforms) = preSolution
-        Debug|Win32 = Debug|Win32
-        Release|Win32 = Release|Win32
+        Debug|$platform = Debug|$platform
+        Release|$platform = Release|$platform
     EndGlobalSection
     GlobalSection(ProjectConfigurationPlatforms) = postSolution
 EOF
@@ -435,10 +439,10 @@ EOF
         foreach my $proj (@{$self->{projects}->{$fld}})
         {
             print SLN <<EOF;
-        $proj->{guid}.Debug|Win32.ActiveCfg = Debug|Win32
-        $proj->{guid}.Debug|Win32.Build.0  = Debug|Win32
-        $proj->{guid}.Release|Win32.ActiveCfg = Release|Win32
-        $proj->{guid}.Release|Win32.Build.0 = Release|Win32
+        $proj->{guid}.Debug|$platform.ActiveCfg = Debug|$platform
+        $proj->{guid}.Debug|$platform.Build.0  = Debug|$platform
+        $proj->{guid}.Release|$platform.ActiveCfg = Release|$platform
+        $proj->{guid}.Release|$platform.Build.0 = Release|$platform
 EOF
         }
     }
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index e165b33..4c417c6 100755
--- a/src/tools/msvc/clean.bat
+++ b/src/tools/msvc/clean.bat
@@ -9,8 +9,13 @@ if exist ..\msvc if exist ..\..\..\src cd ..\..\..

 if exist debug rd /s /q debug
 if exist release rd /s /q release
+if exist _UpgradeReport_Files rd /s /q _UpgradeReport_Files
+for %%f in (UpgradeLog*.xml) do del %%f
+for %%f in (*.old) do del %%f
+for %%f in (*.user) do del %%f
 for %%f in (*.vcproj) do del %%f
 if exist pgsql.sln del /q pgsql.sln
+if exist pgsql.ncb del /q pgsql.ncb
 del /s /q src\bin\win32ver.rc 2> NUL
 del /s /q src\interfaces\win32ver.rc 2> NUL
 if exist src\backend\win32ver.rc del /q src\backend\win32ver.rc
diff --git a/src/tools/msvc/config.pl b/src/tools/msvc/config.pl
index 1e37505..fe884bb 100644
--- a/src/tools/msvc/config.pl
+++ b/src/tools/msvc/config.pl
@@ -3,6 +3,11 @@ use strict;
 use warnings;

 our $config = {
+    msvc_version=>1400,          # 1400 = VC 2005, 1500 = VC 2008
+    platform=>'Win32',        # 'Win32' for x86, 'x64' for x64
+    compiler_opt=>'',         # additional compiler command line arguments
+    linker_opt=>'',           # additional linker command line arguments
+
     asserts=>0,            # --enable-cassert
     # integer_datetimes=>1,   # --enable-integer-datetimes - on is now default
     # float4byval=>1,         # --disable-float4-byval, on by default
diff --git a/src/tools/msvc/gendef.pl b/src/tools/msvc/gendef.pl
index d30417c..c942c5b 100644
--- a/src/tools/msvc/gendef.pl
+++ b/src/tools/msvc/gendef.pl
@@ -5,24 +5,36 @@ my @def;
 # $PostgreSQL$
 #

-die "Usage: gendef.pl <modulepath>\n" unless ($ARGV[0] =~ /\\([^\\]+$)/);
+die "Usage: gendef.pl <modulepath> <platform>\n" unless ($ARGV[0] =~ /\\([^\\]+$)/ && ($ARGV[1] == 'Win32' || $ARGV[1]
=='x64')); 
 my $defname = uc $1;

-if (-f "$ARGV[0]/$defname.def")
+# First, change to the project directory.  Instead of producing symbol.out in the root directory
+# like before and then and renaming it to (configuration)/project/(object file).sym, we directly
+# output the symbol table as ((object file base name).sym.  The reason for doing this is that when
+# compiling in parallel, several attempts might be made to work on the same file (symbols.out)
+# but this way we can keep everything separate.
+chdir($ARGV[0]);
+
+if (-f "$defname.def")
 {
     print "Not re-generating $defname.DEF, file already exists.\n";
     exit(0);
 }

+# We need access to the platform, because the symbol tables are different for Win32 and x64.
+# The x64 symbols don't have a leading _ character, unlike their 32-bit counterparts
+$platform = $ARGV[1];
+
 print "Generating $defname.DEF from directory $ARGV[0]\n";

-while (<$ARGV[0]/*.obj>)
+while (<*.obj>)
 {
     my $symfile = $_;
-    $symfile=~ s/\.obj$/.sym/i;
+    $symfile =~ s/\.obj$/.sym/i;
+
     print ".";
-    system("dumpbin /symbols /out:symbols.out $_ >NUL") && die "Could not call dumpbin";
-    open(F, "<symbols.out") || die "Could not open symbols.out for $_\n";
+    system("dumpbin /symbols /out:$symfile $_ >NUL") && die "Could not call dumpbin";
+    open(F, "<$symfile") || die "Could not open $symfile for $_\n";
     while (<F>)
     {
         s/\(\)//g;
@@ -43,11 +55,10 @@ while (<$ARGV[0]/*.obj>)
         push @def, $pieces[6];
     }
     close(F);
-    rename("symbols.out",$symfile);
 }
 print "\n";

-open(DEF,">$ARGV[0]/$defname.def") || die "Could not write to $defname\n";
+open(DEF,">$defname.def") || die "Could not write to $defname\n";
 print DEF "EXPORTS\n";
 my $i = 0;
 my $last = "";
@@ -55,7 +66,7 @@ foreach my $f (sort @def)
 {
     next if ($f eq $last);
     $last = $f;
-    $f =~ s/^_//;
+    $f =~ s/^_// if ($platform eq 'Win32');
     $i++;

     #   print DEF "  $f \@ $i\n";  # ordinaled exports?
--
1.6.4


pgsql-hackers by date:

Previous
From: Brar Piening
Date:
Subject: Re: Application name patch - v4
Next
From: Euler Taveira de Oliveira
Date:
Subject: Re: ProcessUtility_hook