From b712f599c63e18fdea06e433e0d24e8eee3e1ffd Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Feb 2004 01:38:54 +0000 Subject: [PATCH] Versioned library symbols from Nicolas Boullis. Much appreciated. --- lib/Makefile.am | 82 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index 163ec3fe..de707f71 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.19 2004/02/09 10:32:35 rocky Exp $ +# $Id: Makefile.am,v 1.20 2004/02/10 01:38:54 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -29,7 +29,7 @@ # faster. # # 3. If the library source code has changed at all since the last -# update, then increment REVISION (`C:R:A' becomes `C:r+1:A'). +# update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). # # 4. If any interfaces have been added, removed, or changed since the # last update, increment CURRENT, and set REVISION to 0. @@ -83,7 +83,7 @@ libcdio_sources = \ lib_LTLIBRARIES = libcdio.la libiso9660.la libcdio_la_SOURCES = $(libcdio_sources) -libcdio_la_LDFLAGS = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE) +libcdio_la_LDFLAGS = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE) -Wl,--version-script=libcdio.la.ver libiso9660_la_SOURCES = \ iso9660.c \ @@ -92,6 +92,80 @@ libiso9660_la_SOURCES = \ xa.c libiso9660_la_LIBADD = $(LIBCDIO_LIBS) -libiso9660_la_LDFLAGS = -version-info $(libiso9660_la_CURRENT):$(libiso9660_la_REVISION):$(libiso9660_la_AGE) +libiso9660_la_LDFLAGS = -version-info $(libiso9660_la_CURRENT):$(libiso9660_la_REVISION):$(libiso9660_la_AGE) -Wl,--version-script=libiso9660.la.ver + +# An explanation of the versioning problem from Nicolas Boullis and +# the versioned symbol solution he uses below... +# +# Currently, libvcdinfo uses the cdio_open function from libcdio. +# Let's imagine a program foobar that uses both the vcdinfo_open +# function from libvcdinfo and the cdio_open function from libcdio. + +# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME +# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both +# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine. +# +# Now, for some reason, you decide to change the cdio_open function. +# That's your right, but you have to bump the CURRENT version and (if I +# understand it correctly, athough this is not that clear in libtool's +# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is +# sane since the interface changes incompatibly. + +# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and +# foobar still require libcdio.so.0. Everything is still fine. + +# Now, after some minor changes, the author of foobar recompiles foobar. +# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar +# now segfaults... + +# What is happening? When you run foobar, if brings both libvcdinfo.so.0 +# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you +# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the +# global namespace. Hence, you have to incompatible versions of the +# cdio_open function in the name space. When foobar calls cdio_open, it +# may choose the wrong function, and segfaults... + +# With versioned symbols, the cdio_open function from libcdio.so.0 may be +# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open +# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of +# libcdio would still be brought in by the most recent foobar, but foobar +# (and libvcdinfo) know which versioned function to use and then use the +# good one. + + +# This is some simple versioning where every symbol is versioned with +# something that looks like the SONAME of the library. More complex (and +# better) versioning is possible; it is for example what is used by glibc. +# But good complex versioning is something that requires much more +# work... + + +# The below is a impliments symbol versioning. First of all, I +# compute MAJOR as CURENT - AGE; that is what is used within libtool +# (at least on GNU/Linux systems) for the number in the SONAME. The +# nm command gives the list of symbols known in each of the object +# files that will be part of the shared library. And the sed command +# extracts from this list those symbols that will be shared. (This sed +# command comes from libtool.) + +libcdio_la_MAJOR := $(shell expr $(libcdio_la_CURRENT) - $(libcdio_la_AGE)) +libcdio_la_DEPENDENCIES = libcdio.la.ver + +libcdio.la.ver: $(libcdio_la_OBJECTS) + echo 'CDIO_$(libcdio_la_MAJOR) { ' > $@ + echo " global:" >> $@ + nm $(patsubst %lo,%o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/ \1;/p' | sort | uniq >> $@ + echo '};' >> $@ + +libiso9660_la_MAJOR := $(shell expr $(libiso9660_la_CURRENT) - $(libiso9660_la_AGE)) +libiso9660_la_DEPENDENCIES = $(LIBCDIO_LIBS) libiso9660.la.ver + +libiso9660.la.ver: $(libiso9660_la_OBJECTS) + echo 'ISO9660_$(libiso9660_la_MAJOR) {' > $@ + echo " global:" >> $@ + nm $(patsubst %lo,%o,$(libiso9660_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/ \1;/p' | sort | uniq >> $@ + echo '};' >> $@ + +MOSTLYCLEANFILES = libcdio.la.ver libiso9660.la.ver INCLUDES = -I$(LIBCDIO_CFLAGS)