[Please CC any replies, thanks]

NOTE: I am not requesting that this patch is integrated, only that it
exists in the archive in case future problems emerge requiring it. It's
essentially something that only works for Linux and select other OSes
and the bug it fixes is somewhat outside the scope of the PostgreSQL
community (see below).

This patch:
a) When building a shared library on Linux and an exports.txt file
exists, it will generate an appropriate version script for ld to limit
the symbols exported.

b) Additionally, if SHLIB_VERSION is defined in the Makefile, the
symbols of the library will be versioned with that version.

The net effect is that the exported symbol list from libpq (the only
lib with an exports file) drops from 216 symbols to the 123 listed as

The bug I'm referring to is somewhat theoretical in that I don't think
anyone's run into it, but you never know. Say someone starts with
Debian Unstable today and installs postgresql-8.0 and libnss-pgsql1.
The former is linked against libpq4, the latter against libpq3 but they
have largely the same symbols. The user then configures libnss-pgsql
for hostname lookups and starts psql to connect to a remote server.

psql then does a gethostbyname which goes via NSS to dlopen
libnss-pgsql and its symbols will be linked against libpq4 because
they're already loaded. Any remaining symbols will be resolved against
libpq3. Finally, any global symbols in libpq3 that have a symbol of the
same name in libpq4 will be resolved against the version in libpq4. I
don't think I need to explain that this situation may have undefined

Note: rpath won't save you hare since that applies to finding
libraries, but doesn't affect symbol lookup order. The above will also
apply if above user compiles their own version of postgresql but not

Symbol versioning solves this in that each library and program will
link to the version it expects. This patch paves the way. And if the
user deletes the other library in an attempt to make it work, they get
a helpful message like:

./psql: $PATH/libpq.so.4: version `LIBPQ_4.1' not found (required by ./psql)

Note, this is the only reason I would expect it to be adopted by core,
for debugging purposes. The only time versioning may cause
incompatabilities is if different distributions start versioning the
same library differently. Unversioned binaries work against versioned
libs and vice-versa.

Hence, we should at least get straight the tags. I suggest:


This is in line with how other libraries do it (eg GLIBC_2.0) and
provides maximum differentiation. It's not like we're trying to provide
any kind of backward compatability at that level.

This patch will work on any system using GNU ld and where the system
dynamic linker supports versioned symbols. The only one I'm sure of is
Linux but others are easily added.

Thanks for your attention,
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.
Index: src/Makefile.shlib
RCS file: /projects/cvsroot/pgsql/src/Makefile.shlib,v
retrieving revision 1.97
diff -u -r1.97 Makefile.shlib
--- src/Makefile.shlib  8 Aug 2005 03:35:13 -0000       1.97
+++ src/Makefile.shlib  18 Oct 2005 17:54:10 -0000
@@ -184,6 +184,12 @@
 ifeq ($(PORTNAME), linux)
   LINK.shared          = $(COMPILER) -shared -Wl,-soname,$(soname)
+  ifeq ($(wildcard exports.txt),exports.txt)
+    LINK.shared        += -Wl,--version-script,exports.gnuld
+    EXPORTS_FILE        = exports.gnuld
+  endif
 ifeq ($(PORTNAME), solaris)
@@ -255,6 +261,12 @@
 endif # enable_shared
+# If you wish to version the symbols, just define SHLIB_VERSION to be
+# something like LIBPQ_4.1 in the Makefile for that library. Otherwise the
+# symbols will be unversioned (as per default). Produced version script is
+# for GNU ld only and is currently created only on Linux.
+exports.gnuld: exports.txt
+       awk 'BEGIN { print "$(SHLIB_VERSION) { global: " } { if( $$1 != "#" ) 
{print $$1,";"} } END { print "local: *; };" }' < $< > $@
@@ -291,7 +303,7 @@
 ifneq ($(PORTNAME), aix)
 # Normal case
-$(shlib): $(OBJS)
+$(shlib): $(OBJS) $(EXPORTS_FILE)
        $(LINK.shared) $(LDFLAGS_SL) $(OBJS) $(SHLIB_LINK) -o $@
 # If we're using major and minor versions, then make a symlink to 
 ifneq ($(shlib), $(shlib_major))
@@ -411,7 +423,7 @@
        rm -f lib$(NAME).a
 ifeq ($(enable_shared), yes)
-       rm -f $(shlib_bare) $(shlib_major) $(shlib)
+       rm -f $(shlib_bare) $(shlib_major) $(shlib) $(EXPORTS_FILE)
 ifdef EXPSUFF
        rm -f lib$(NAME)$(EXPSUFF)

Attachment: pgppAeQeyPWSU.pgp
Description: PGP signature

Reply via email to