Обсуждение: Building Windows Server Extensions Using VC++ 2005

Поиск
Список
Период
Сортировка

Building Windows Server Extensions Using VC++ 2005

От
"Charles F. I. Savage"
Дата:
Hi everyone,

I've been able to successfully build server extension using Visual 
Studio 2005 for Windows Postgresql 8.1.  However, it took a few tweaks 
which I thought I should document (maybe these issues could be fixed in 
future postgresql versions?):


1.  There is no lib file for VC++ to link against.  This can be created 
easily enough by going to src/backend directory and running:

lib /MACHINE:x86 /NAME:postgres.exe /DEF:postgres.def

Note the use of /NAME to tell VC++ it is linking against an executable 
and not a dll.

It would be nice if this lib file was automatically installed on windows 
when installing postgresql.


2.  Requirement on strings.h

In c.h:69 there is this code:

#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif


In pg_config.h:405 this is defined:

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

However, Visual Studio 2005 does not include this file.  For a 
workaround I simply added it but that's a bit of hack.


3.  This is a bigger issue, and took a while to figure out. If you try 
to use the Version 1 calling convention, your function will be called 
but if you try to do anything with the passed in parameters a 
segmentation fault will occur.  If you use the Version 0 calling 
convention things work fine.

The problem is if you use PG_FUNCTION_INFO_V1 postgres does not see the 
generated function because it is not exported from the dll and thus 
assumes the Version 0 calling convention when in fact your function is 
using Version1.  The problem is in fmgr.h:298

#define PG_FUNCTION_INFO_V1(funcname) \

extern  Pg_finfo_record * CppConcat(pg_finfo_,funcname) (void); \
...

For windows to export this function it must be:

extern __declspec(dllexport) Pg_finfo_record * 
CppConcat(pg_finfo_,funcname) (void);

Would it be possible to add a DLLEXPORT macro here to fix this?


4.  Last, and the biggest issue, if my function calls pfree it blows 
up.  What is happening is that pfree somehow ends up pointing to a 
random spot in memory - thus when you try to call it you execute invalid 
code (in fact you never execute pfree at all as far as I can see).  I 
worked around this by using pgport_pfree which does work.  Haven't a 
clue why...


Here is the assembly for successfully calling pgport_pfree:

pgport_pfree(fileName);
100112D3  mov         eax,dword ptr [ebp-0Ch]
100112D6  push        eax  
100112D7  call        100110C3
100112DC  add         esp,4

100110C3  jmp         1001131A

pgport_pfree:
1001131A  jmp         dword ptr ds:[10016288h]

005CF140  push        ebp  
005CF141  mov         ebp,esp
005CF143  sub         esp,8
005CF146  mov         eax,dword ptr [ebp+8]
005CF149  mov         dword ptr [esp+4],eax
005CF14D  mov         eax,dword ptr ds:[006A9F94h]
005CF152  mov         dword ptr [esp],eax
005CF155  call        005CF0D0
005CF15A  leave            
005CF15B  ret              


And here is pfree.  Note at the end the code tries to execute "db" at 
005E1560 causing a segmentation fault.

pfree( fileName );
100112D3  mov         eax,dword ptr [ebp-0Ch]
100112D6  push        eax  
100112D7  call        1001110E
100112DC  add         esp,4

1001110E  jmp         10011238

pfree:
10011238  jmp         dword ptr ds:[1001628Ch]

005E1560  db          ffh  


Hope this helps others.  It would be great if building postgresql server 
extensions with VC++ worked out of the box on Windows (in addition of 
course to using MingW) since I think it would open up a wider audience.

Charlie

Re: Building Windows Server Extensions Using VC++ 2005

От
Bruce Momjian
Дата:
Charles F. I. Savage wrote:
> Hi everyone,
>
> I've been able to successfully build server extension using Visual
> Studio 2005 for Windows Postgresql 8.1.  However, it took a few tweaks
> which I thought I should document (maybe these issues could be fixed in
> future postgresql versions?):

Sorry for the delay in replying to your issues.

> 1.  There is no lib file for VC++ to link against.  This can be created
> easily enough by going to src/backend directory and running:
>
> lib /MACHINE:x86 /NAME:postgres.exe /DEF:postgres.def
>
> Note the use of /NAME to tell VC++ it is linking against an executable
> and not a dll.
>
> It would be nice if this lib file was automatically installed on windows
> when installing postgresql.

We don't distribute a *.def file in this case because it would be too
hard to keep it up-to-date.  We have *.def files for libpq, but that
changes much less frequently than the backend.  The most reliable
solution is for users to generate the file themselves.

> 2.  Requirement on strings.h
>
> In c.h:69 there is this code:
>
> #ifdef HAVE_STRINGS_H
> #include <strings.h>
> #endif
>
>
> In pg_config.h:405 this is defined:
>
> /* Define to 1 if you have the <strings.h> header file. */
> #define HAVE_STRINGS_H 1
>
> However, Visual Studio 2005 does not include this file.  For a
> workaround I simply added it but that's a bit of hack.

Ah, so even though you are using MSVC, you are using the config file
from MinGW.  Easy fix, included in the patch below, and applied for 8.2.

> 3.  This is a bigger issue, and took a while to figure out. If you try
> to use the Version 1 calling convention, your function will be called
> but if you try to do anything with the passed in parameters a
> segmentation fault will occur.  If you use the Version 0 calling
> convention things work fine.
>
> The problem is if you use PG_FUNCTION_INFO_V1 postgres does not see the
> generated function because it is not exported from the dll and thus
> assumes the Version 0 calling convention when in fact your function is
> using Version1.  The problem is in fmgr.h:298
>
> #define PG_FUNCTION_INFO_V1(funcname) \
>
> extern  Pg_finfo_record * CppConcat(pg_finfo_,funcname) (void); \
> ...
>
> For windows to export this function it must be:
>
> extern __declspec(dllexport) Pg_finfo_record *
> CppConcat(pg_finfo_,funcname) (void);
>
> Would it be possible to add a DLLEXPORT macro here to fix this?

Yes, we can add DLLIMPORT (which is our macro for that).

However, looking at why /contrib works for MinGW, I think it is the use
of this from Makefile.shlib:

       $(DLLTOOL) --export-all $(DLLTOOL_DEFFLAGS) --output-def $(NAME).def $(OBJS)

I am thinking you should just do the same for MSVC.  Should we add
DLLIMPORT to PG_FUNCTION_INFO_V1()?  It duplicates --export-all but it
seems like the correct solution.

> 4.  Last, and the biggest issue, if my function calls pfree it blows
> up.  What is happening is that pfree somehow ends up pointing to a
> random spot in memory - thus when you try to call it you execute invalid
> code (in fact you never execute pfree at all as far as I can see).  I
> worked around this by using pgport_pfree which does work.  Haven't a
> clue why...

The answer is in a comment just above pgport_palloc():

    /*
     *  Memory support routines for libpgport on Win32
     *
     *  Win32 can't load a library that DLLIMPORTs a variable
     *  if the link object files also DLLIMPORT the same variable.
     *  For this reason, libpgport can't reference CurrentMemoryContext
     *  in the palloc macro calls.
     *
     *  To fix this, we create several functions here that allow us to
     *  manage memory without doing the inline in libpgport.
     */

--
  Bruce Momjian   http://candle.pha.pa.us
  SRA OSS, Inc.   http://www.sraoss.com

  + If your life is a hard drive, Christ can be your backup. +
Index: src/include/c.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/c.h,v
retrieving revision 1.196
diff -c -c -r1.196 c.h
*** src/include/c.h    16 Feb 2006 23:23:50 -0000    1.196
--- src/include/c.h    3 Mar 2006 17:13:57 -0000
***************
*** 66,72 ****
  #include <string.h>
  #include <stddef.h>
  #include <stdarg.h>
! #ifdef HAVE_STRINGS_H
  #include <strings.h>
  #endif
  #include <sys/types.h>
--- 66,73 ----
  #include <string.h>
  #include <stddef.h>
  #include <stdarg.h>
! /* Some use MinGW-generated pg_config.h but MSVC for extensions. */
! #if defined(HAVE_STRINGS_H) && !defined(WIN32_CLIENT_ONLY)
  #include <strings.h>
  #endif
  #include <sys/types.h>