On Wed, 2007-11-07 at 16:31 -0500, Behdad Esfahbod wrote:
> On Wed, 2007-11-07 at 21:46 +0100, Alexander Larsson wrote:
> > 
> > This leads me to belive it should be possible to create a configure
> > option for glib such that libglib, libgmodule, libgobject are in the
> > same libglib.so file, and with symlinks for gmodule and gobject. This
> > setup should allow all old binaries to work as they used to, plus apps
> > linked against this setup will continue to work in systems using the old
> > setup.

After talking to jakub I came up with a better approach for this. 
Consider the case of merging libglib and libgobject. We make libglib.so
and libgobject.so small libraries that only contain the symbols from the
respective real library. These libraries are what are picked by the
linker (ld) when you specify -lglib and -lgobject, and the symbols in
them are verified against what the app uses (so you get errors if you
reference symbols that are not in the libs). 

However, in the resulting binary the DT_NEEDED is encoded based on the
DT_SONAME of these libraries. In our case the sonames of these libraries
is libglib.so.0 and libgobject.so.0. These are the things looked up by
the runtime linker (ld.so) when finding the library to load for the app.
However, we make both libglib.so.0 and libgobject.so.0 symlinks to the
same file, libglib_combined.so.0, which contains all the object files
from glib and gobjects in one shared object.

So, the result is:
a) binaries have the same dependencies as before (i.e on both libs)
b) however, we only load one library, meaning less linker overhead
c) and that library is actually smaller than the two separate ones as
in-library calls can now be optimized

There is a slight problem with ldconfig. It goes throught the
$prefix/lib directory and "fixes" up all symlinks based on the actual
soname in the files. This means it will change the libglib.so.0 symlink
to point to libglib.so, totally breaking things. I've worked around this
by having the dummy library be in another directory
($libdir/glib-2.0/dummy/) which causes ldconfig not to change anything.

I've attached a patch that gives a --enable-combined feature which
combines glib, gobject and gmodule. (Not gthread, because linking in
libpthreads causes slowdown since e.g. all mallocs etc suddenly become
threadsafe with locking.)

I tested this patch by just starting gedit and then looking
at /proc/pid/smaps. The total combined rss/vmsize before combination was
712kb/984kb, and afterwards it was 688kb/964kb. In addition each of the
three libraries had 4k private dirty memory, which was reduced to only
one in the combined case. So, 24kb less RSS, 20k less vmsize and 8k less
private dirty memory (this is per process using glib).

For some reason the combined version also uses 8k less RSS in libgtk.
I'm not sure why that is. Maybe just random fluctuations.

Anyway, I can't think of any negative aspects about this, appart from
the additional dependency on libdl.so for apps linking to glib. Sounds
like a good idea to me.

Index: combined/Makefile.am
===================================================================
--- combined/Makefile.am	(revision 0)
+++ combined/Makefile.am	(revision 0)
@@ -0,0 +1,36 @@
+## Process this file with automake to produce Makefile.in
+
+lib_LTLIBRARIES = libglib_combined-2.0.la 
+
+export_symbols = $(LIBTOOL_EXPORT_OPTIONS)
+
+libglib_combined_2_0_la_SOURCES =
+libglib_combined_2_0_la_LIBADD = ../glib/libglib-noin-2.0.la ../gobject/libgobject-noin-2.0.la ../gmodule/libgmodule-noin-2.0.la
+libglib_combined_2_0_la_DEPENDENCIES = ../glib/libglib-noin-2.0.la ../gobject/libgobject-noin-2.0.la ../gmodule/libgmodule-noin-2.0.la
+libglib_combined_2_0_la_LDFLAGS = \
+	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+	-export-dynamic $(export_symbols)
+
+install-exec-local:
+	rm -f $(DESTDIR)$(libdir)/libglib-2.0.so
+	ln -s glib-2.0/dummy/libglib-2.0.so $(DESTDIR)$(libdir)/libglib-2.0.so
+	rm -f $(DESTDIR)$(libdir)/libglib-2.0.so.0
+	rm -f $(DESTDIR)$(libdir)/libglib-2.0.so.0.$(LT_CURRENT).$(LT_REVISION)
+	ln -s libglib_combined-2.0.so.0.$(LT_CURRENT).$(LT_REVISION) $(DESTDIR)$(libdir)/libglib-2.0.so.0.$(LT_CURRENT).$(LT_REVISION)
+	ln -s libglib-2.0.so.0.$(LT_CURRENT).$(LT_REVISION) $(DESTDIR)$(libdir)/libglib-2.0.so.0
+
+	rm -f $(DESTDIR)$(libdir)/libgobject-2.0.so
+	ln -s glib-2.0/dummy/libgobject-2.0.so $(DESTDIR)$(libdir)/libgobject-2.0.so
+	rm -f $(DESTDIR)$(libdir)/libgobject-2.0.so.0
+	rm -f $(DESTDIR)$(libdir)/libgobject-2.0.so.0.$(LT_CURRENT).$(LT_REVISION)
+	ln -s libglib_combined-2.0.so.0.$(LT_CURRENT).$(LT_REVISION) $(DESTDIR)$(libdir)/libgobject-2.0.so.0.$(LT_CURRENT).$(LT_REVISION)
+	ln -s libgobject-2.0.so.0.$(LT_CURRENT).$(LT_REVISION) $(DESTDIR)$(libdir)/libgobject-2.0.so.0
+	ls -l /gnome/head/INSTALL/lib/libglib*
+
+	rm -f $(DESTDIR)$(libdir)/libgmodule-2.0.so
+	ln -s glib-2.0/dummy/libgmodule-2.0.so $(DESTDIR)$(libdir)/libgmodule-2.0.so
+	rm -f $(DESTDIR)$(libdir)/libgmodule-2.0.so.0
+	rm -f $(DESTDIR)$(libdir)/libgmodule-2.0.so.0.$(LT_CURRENT).$(LT_REVISION)
+	ln -s libglib_combined-2.0.so.0.$(LT_CURRENT).$(LT_REVISION) $(DESTDIR)$(libdir)/libgmodule-2.0.so.0.$(LT_CURRENT).$(LT_REVISION)
+	ln -s libgmodule-2.0.so.0.$(LT_CURRENT).$(LT_REVISION) $(DESTDIR)$(libdir)/libgmodule-2.0.so.0
+	ls -l /gnome/head/INSTALL/lib/libglib*
Index: dummylib.sh
===================================================================
--- dummylib.sh	(revision 0)
+++ dummylib.sh	(revision 0)
@@ -0,0 +1,41 @@
+#!/bin/sh
+F=`file -L $1`
+C=
+S=8
+case "$F" in
+  *ELF\ 64-bit*shared\ object*x86-64*) C=-m64;;
+  *ELF\ 32-bit*shared\ object*80?86*) C=-m32; S=4;;
+  *ELF\ 64-bit*shared\ object*PowerPC*) C=-m64;;
+  *ELF\ 32-bit*shared\ object*PowerPC*) C=-m32; S=4;;
+  *ELF\ 64-bit*shared\ object*cisco*) C=-m64;;
+  *ELF\ 32-bit*shared\ object*cisco*) C=-m32; S=4;;
+  *ELF\ 64-bit*shared\ object*IA-64*) C=;;
+  *ELF\ 64-bit*shared\ object*Alpha*) C=;;
+  *ELF\ 64-bit*shared\ object*390*) C=-m64;;
+  *ELF\ 32-bit*shared\ object*390*) C=-m31; S=4;;
+  *ELF\ 64-bit*shared\ object*SPARC*) C=-m64;;
+  *ELF\ 32-bit*shared\ object*SPARC*) C=-m32; S=4;;
+  *ELF\ 64-bit*shared\ object*Alpha*) C=;;
+esac
+readelf -Ws $1 | awk '
+/\.dynsym.* contains/ { start=3 }
+/^$/ { start=0 }
+/  UND / { next }
+ {
+  if (start > 1)
+    start = start - 1;
+  else if (start == 1) {
+  fn=$8
+  if ($4 ~ /FUNC/) { print ".text"; size=16; print ".type " fn ",@function" }
+  else if ($4 ~ /OBJECT/) { print ".data"; size=$3; print ".type " fn ",@object" }
+  else if ($4 ~ /NOTYPE/) { print ".data"; size=$3 }
+  else exit(1);
+  print ".globl " fn
+  if ($5 ~ /WEAK/) { print ".weak " fn }
+  else if ($5 !~ /GLOBAL/) exit(1);
+  print fn ": .skip " size
+  print ".size " fn "," size
+} }
+' > lib.s || exit
+gcc $C -shared -Wl,-soname,$3 -o $2 lib.s -nostdlib
+strip $2

Property changes on: dummylib.sh
___________________________________________________________________
Name: svn:executable
   + *

Index: gmodule/Makefile.am
===================================================================
--- gmodule/Makefile.am	(revision 5790)
+++ gmodule/Makefile.am	(working copy)
@@ -69,17 +69,20 @@
 gmodule_win32_res_ldflag = -Wl,$(gmodule_win32_res)
 endif
 
-libgmodule_2_0_la_SOURCES = gmodule.c
+libgmodule_noin_2_0_la_SOURCES = gmodule.c
+libgmodule_noin_2_0_la_LIBADD = $(G_MODULE_LIBS_EXTRA) $(G_MODULE_LIBS) $(libglib)
+libgmodule_noin_2_0_la_DEPENDENCIES = $(gmodule_win32_res) $(GMODULE_DEF)
+
+
+libgmodule_2_0_la_SOURCES = 
 libgmodule_2_0_la_LDFLAGS = \
 	$(gmodule_win32_res_ldflag) \
 	$(G_MODULE_LDFLAGS) \
 	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
 	-export-dynamic $(no_undefined) $(export_symbols)
 
-libgmodule_2_0_la_LIBADD = $(G_MODULE_LIBS_EXTRA) $(G_MODULE_LIBS) $(libglib)
+libgmodule_2_0_la_LIBADD = libgmodule-noin-2.0.la
 
-libgmodule_2_0_la_DEPENDENCIES = $(gmodule_win32_res) $(GMODULE_DEF)
-
 if OS_WIN32
 gmodule-win32-res.o: gmodule.rc
 	$(WINDRES) gmodule.rc $@
@@ -108,3 +111,26 @@
 install-data-local: install-ms-lib install-def-file
 
 uninstall-local: uninstall-ms-lib uninstall-def-file
+
+if ENABLE_COMBINED
+noinst_LTLIBRARIES = libgmodule-noin-2.0.la
+
+libgmodule-dummy-2.0.la:
+	$(LINK) -rpath `pwd` \
+	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+	-export-dynamic $(no_undefined) $(export_symbols) \
+	libgmodule-noin-2.0.la
+
+libgmodule-dummy-2.0.so: libgmodule-dummy-2.0.la
+	../dummylib.sh .libs/libgmodule-dummy-2.0.so.0 libgmodule-dummy-2.0.so libgmodule-2.0.so.$(LT_CURRENT_MINUS_AGE)
+
+install-dummy-lib: libgmodule-dummy-2.0.so
+	mkdir -p $(DESTDIR)$(libdir)/glib-2.0/dummy/
+	$(INSTALL) $(INSTALL_STRIP_FLAG) libgmodule-dummy-2.0.so $(DESTDIR)$(libdir)/glib-2.0/dummy/libgmodule-2.0.so
+
+install-exec-local: install-ms-lib install-dummy-lib
+
+
+# Make sure to not actually install libmodule-2.0.so
+install-libLTLIBRARIES:
+endif
Index: gobject/Makefile.am
===================================================================
--- gobject/Makefile.am	(revision 5790)
+++ gobject/Makefile.am	(working copy)
@@ -77,10 +77,12 @@
   -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
   -export-dynamic $(no_undefined) $(export_symbols)
 
-libgobject_2_0_la_LIBADD = $(libglib)
+libgobject_2_0_la_LIBADD = libgobject-noin-2.0.la
 
-libgobject_2_0_la_DEPENDENCIES = $(gobject_win32_res) $(GOBJECT_DEF)
+libgobject_noin_2_0_la_LIBADD = $(libglib)
 
+libgobject_noin_2_0_la_DEPENDENCIES = $(gobject_win32_res) $(GOBJECT_DEF)
+
 #
 # setup source file variables
 #
@@ -197,7 +199,8 @@
 
 # target platform:
 libgobjectinclude_HEADERS = $(gobject_target_headers)
-libgobject_2_0_la_SOURCES = $(gobject_target_sources)
+libgobject_2_0_la_SOURCES = 
+libgobject_noin_2_0_la_SOURCES = $(gobject_target_sources)
 
 #
 # programs to compile and install
@@ -259,3 +262,26 @@
 	if test $(srcdir) = .; then :; else \
 	    rm -f $(BUILT_EXTRA_DIST); \
 	fi
+
+if ENABLE_COMBINED
+noinst_LTLIBRARIES = libgobject-noin-2.0.la
+
+libgobject-dummy-2.0.la:
+	$(LINK) -rpath `pwd` \
+	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+	-export-dynamic $(no_undefined) $(export_symbols) \
+	libgobject-noin-2.0.la
+
+libgobject-dummy-2.0.so: libgobject-dummy-2.0.la
+	../dummylib.sh .libs/libgobject-dummy-2.0.so.0 libgobject-dummy-2.0.so libgobject-2.0.so.$(LT_CURRENT_MINUS_AGE)
+
+install-dummy-lib: libgobject-dummy-2.0.so
+	mkdir -p $(DESTDIR)$(libdir)/glib-2.0/dummy/
+	$(INSTALL) $(INSTALL_STRIP_FLAG) libgobject-dummy-2.0.so $(DESTDIR)$(libdir)/glib-2.0/dummy/libgobject-2.0.so
+
+install-exec-local: install-ms-lib install-dummy-lib
+
+# Make sure to not actually install libgobject-2.0.so
+install-libLTLIBRARIES:
+
+endif
Index: glib/Makefile.am
===================================================================
--- glib/Makefile.am	(revision 5790)
+++ glib/Makefile.am	(working copy)
@@ -86,7 +86,7 @@
 uninstall-ms-lib:
 endif
 
-libglib_2_0_la_SOURCES = 	\
+libglib_noin_2_0_la_SOURCES = 	\
 	garray.c		\
 	gasyncqueue.c		\
 	gatomic.c		\
@@ -153,7 +153,7 @@
 	gprintf.c		\
 	gprintfint.h
 
-EXTRA_libglib_2_0_la_SOURCES = \
+EXTRA_libglib_noin_2_0_la_SOURCES = \
 	giounix.c	\
 	giowin32.c	\
 	gspawn.c	\
@@ -271,9 +271,11 @@
 pcre_inc =
 endif
 
-libglib_2_0_la_LIBADD = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ @ICONV_LIBS@ @G_LIBS_EXTRA@ $(pcre_lib)
-libglib_2_0_la_DEPENDENCIES = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ $(glib_win32_res) @GLIB_DEF@
+libglib_noin_2_0_la_LIBADD = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ @ICONV_LIBS@ @G_LIBS_EXTRA@ $(pcre_lib)
+libglib_noin_2_0_la_DEPENDENCIES = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ $(glib_win32_res) @GLIB_DEF@
 
+libglib_2_0_la_SOURCES =
+libglib_2_0_la_LIBADD = libglib-noin-2.0.la
 libglib_2_0_la_LDFLAGS = \
 	 $(glib_win32_res_ldflag) \
 	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
@@ -300,3 +302,27 @@
 	for f in $$files; do \
 	  if test -f $$f; then d=.; else d=$(srcdir); fi; \
 	  cp $$d/$$f $(distdir) || exit 1; done
+
+
+if ENABLE_COMBINED
+noinst_LTLIBRARIES = libglib-noin-2.0.la 
+
+libglib-dummy-2.0.la:
+	$(LINK) -rpath `pwd` \
+	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+	-export-dynamic $(no_undefined) $(export_symbols) \
+	libglib-noin-2.0.la
+
+libglib-dummy-2.0.so: libglib-dummy-2.0.la
+	../dummylib.sh .libs/libglib-dummy-2.0.so.0 libglib-dummy-2.0.so libglib-2.0.so.$(LT_CURRENT_MINUS_AGE)
+
+install-dummy-lib: libglib-dummy-2.0.so
+	mkdir -p $(DESTDIR)$(libdir)/glib-2.0/dummy/
+	$(INSTALL) $(INSTALL_STRIP_FLAG) libglib-dummy-2.0.so $(DESTDIR)$(libdir)/glib-2.0/dummy/libglib-2.0.so
+
+install-exec-local: install-ms-lib install-dummy-lib
+
+# Make sure to not actually install libglib-2.0.so
+install-libLTLIBRARIES:
+
+endif
Index: configure.in
===================================================================
--- configure.in	(revision 5790)
+++ configure.in	(working copy)
@@ -223,6 +223,10 @@
               [AC_HELP_STRING([--disable-visibility],
                               [don't use ELF visibility attributes])],,
               [enable_visibility=yes])
+AC_ARG_ENABLE(combined,
+              [AC_HELP_STRING([--enable-combined],
+                              [turn on garbage collector friendliness [default=no]])],,
+              [enable_combined=no])
 
 if test "x$enable_threads" != "xyes"; then
   enable_threads=no
@@ -245,6 +249,14 @@
   AC_MSG_RESULT([yes])
 fi
 
+AC_MSG_CHECKING([whether to enable combined glib])
+if test "x$enable_combined" = "xyes"; then
+  AC_MSG_RESULT([yes])
+else
+  AC_MSG_RESULT([no])
+fi
+AM_CONDITIONAL(ENABLE_COMBINED, [test x$enable_combined = xyes])
+
 if test "$glib_native_win32" = "yes"; then
   if test x$enable_static = xyes -o x$enable_static = x; then
     AC_MSG_WARN([Disabling static library build, must build as DLL on Windows.])
@@ -2971,6 +2983,7 @@
 gobject/Makefile
 gobject/glib-mkenums
 gthread/Makefile
+combined/Makefile
 po/Makefile.in
 docs/Makefile
 docs/reference/Makefile
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 5790)
+++ Makefile.am	(working copy)
@@ -2,8 +2,14 @@
 
 AUTOMAKE_OPTIONS = 1.7
 
-SUBDIRS = . m4macros glib gobject gmodule gthread tests build po docs
+if ENABLE_COMBINED
+COMBINE_DIR=combined
+else
+COMBINE_DIR=
+endif
 
+SUBDIRS = . m4macros glib gobject gmodule gthread $(COMBINE_DIR) tests build po docs
+
 bin_SCRIPTS = glib-gettextize
 
 INCLUDES = -DG_LOG_DOMAIN=g_log_domain_glib @GLIB_DEBUG_FLAGS@ \
_______________________________________________
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list

Reply via email to