Thanks a lot for the details. Hopefully, I'll be able to pull it off.
--Mona

--- On Fri, 7/1/11, Craig Ringer <[email protected]> wrote:

From: Craig Ringer <[email protected]>
Subject: Re: [GENERAL] statically compiling postgres and problem with initdb
To: "Tom Lane" <[email protected]>
Cc: "mona attariyan" <[email protected]>, [email protected]
Date: Friday, July 1, 2011, 8:13 PM

On 1/07/2011 11:48 PM, Tom Lane wrote:

> It might be easier to rip out the functionality that expects loadable
> libraries to work.  I think you could probably get through initdb if you
> just disabled creation of encoding-conversion functions and text search
> dictionaries (try #ifdef'ing out the relevant sections of initdb.c).

Good point. If all that's needed is basic functionality...

> Of course, you'll end up with a pretty crippled version of PG --- no
> encoding conversions, no text search, no procedural languages --- but
> maybe that's enough for what you want to do.  If it's not, then as Craig
> says, you're looking at some pretty major work to bind those pieces into
> the executable statically.

I had to do something quite similar for Scribus years ago, and it wasn't 
anywhere near as hard as I'd feared. It did have two  really annoying bits, 
though. One was having to prefix each shared library's public symbols with the 
name of the shared library to avoid conflicts and allow me to differentiate 
different implementations of the same public interfaces. The second was 
modifying the build system to link each library to the main executable.

This is from increasingly vague memory, but:

First I created a function pointer list entry struct type that maps function 
names to function pointers.

I then modified the loader code so it prefixed the function names it was 
expecting with the library name. Instead of "funcname" it'd try to resolve 
"libname_funcname".

I went through EVERY SINGLE LIBRARY and prefixed the library name to the names 
of every non-static function. It was ugly, but the alternative would've been a 
horrid token-pasting macro hack that would've still required changing each 
function declaration.

The libraries already had headers. If they hadn't, I would've had to write a 
header for each library that declared prototypes for its functions.

I added a new header file to the main build that included all the library 
headers and declared a global array of function pointer list entries. In the 
associated .c (well, .cxx in Scribus) I defined the array, populating it with 
the library-name-prefixed function names and pointers to each function.

I modified each site where Scribus used dlopen() and dlsym() so it called them 
via a wrapper. The wrapper for dynamic linking was just a trivial header of 
inline wrappers around dlopen() and dlsym(). The static linking replacement for 
dlopen() just returned the input library name char* as void*, and the dlsym() 
replacement cast the void* back to char*, joined the library name and function 
name, looked the result up in the function pointer list, and returned the 
resulting function pointer.

Finally, I had to modify the build process so it produced static libraries 
instead of shared libraries for each add-on, and modify the final application 
linkage so it linked each library. This was made a lot easier by the fact that 
Scribus used CMake instead of autotools; I don't know what it'd be like to try 
to do this with autohell, but I suspect "ugly" would be a start.

--
Craig Ringe

Reply via email to