This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: install libgtkpeer.so and libjawt.so in versioned library directory
- From: Thomas Fitzsimmons <fitzsim at redhat dot com>
- To: java-patches at gcc dot gnu dot org
- Date: Mon, 29 May 2006 20:57:39 -0400
- Subject: Patch: install libgtkpeer.so and libjawt.so in versioned library directory
Hi,
This patch changes how the GTK peers are handled. Specifically, it:
- eliminates lib-gnu-java-awt-peer-gtk.so, the combined .java and .c peer
library
- installs libgtkpeer.so, the JNI peer library produced by the GNU Classpath
build, in a GCJ-version-specific library directory,
$(libdir)/gcj-$(gcc_version)
- moves the Java objects from lib-gnu-java-awt-peer-gtk.so into libgcj.so
- renames libgcjawt.so to libjawt.so and installs it in the GCJ-version-specific
library directory
- adds an LD_LIBRARY_PATH hack to gij to ensure that libjawt.so and like
libraries are correctly located by gij
- prepends the GCJ-version-specific library directory to libgcj's module load
path
There are several reasons why this approach is better. First, distributions had
problems installing multiple versions of GCJ in parallel because dlopen'd
modules were installed in $(libdir). dlopen first looks for unversioned
modules, meaning that only one version set of modules would be used -- whichever
version owned the unversioned files. Second, it means that applications using
libjawt.so need not explicitly specify an LD_LIBRARY_PATH. Third, this gets us
closer (perhaps the entire way?) to disabling lib-foo-bar library loading,
eliminating many needless open() calls on application startup.
One case that this patch does not handle is automatic LD_LIBRARY_PATH handling
for GCJ-native-compiled libjawt.so applications. Users running such binaries
will have to manually point LD_LIBRARY_PATH at $(libdir)/gcj-$(gcc_version).
When this patch is accepted, I'll submit a corresponding patch to GNU Classpath.
OK to commit?
Tom
2006-05-29 Thomas Fitzsimmons <fitzsim@redhat.com>
* scripts/makemake.tcl (emit_bc_rule): Do not skip
gnu-java-awt-peer-gtk.lo.
Include gnu/java/awt/peer/gtk Java objects in libgcj.so. Use C++
ABI for gnu/java/awt/peer/gtk package.
* gnu/classpath/natSystemProperties.cc (PrependVersionedLibdir):
New function.
(insertSystemProperties): Only set java.ext.dirs if it is not
already defined. Prepend GCJ_VERSIONED_LIBDIR to module search
path where necessary.
* configure.ac (GTK_AWT): Remove automake conditional.
* include/jvm.h (_Jv_PrependVersionedLibdir): New function
declaration.
* gij.cc (main): Prepend LD_LIBRARY_PATH with GCJ_VERSIONED_LIBDIR
and re-exec self.
* Makefile.am (AM_CXXFLAGS): Define GCJ_VERSIONED_LIBDIR,
GIJ_EXECUTABLE and PATH_SEPARATOR macros.
Remove lib-gnu-java-awt-peer-gtk.la and libgcjawt.la build logic.
* prims.cc (_Jv_PrependVersionedLibdir): New function.
2006-05-29 Thomas Fitzsimmons <fitzsim@redhat.com>
* native/jni/gtk-peer/Makefile.am (gcc_version): New variable.
(gcjversionedlibdir): Likewise.
(libgtkpeer_la_LDFLAGS): Likewise.
Install libgtkpeer.so in GCJ versioned library directory.
* native/jawt/Makefile.am (gcc_version): New variable.
(gcjversionedlibdir): Likewise.
(libjawt_la_LDFLAGS): Likewise.
Rename libjawtgnu.so libjawt.so. Install libjawt.so in GCJ
versioned library directory.
* gnu/java/awt/peer/gtk/GdkFontPeer.java (static): Call
System.loadLibrary unconditionally.
* gnu/java/awt/peer/gtk/GdkPixbufDecoder.java: Likewise.
* gnu/java/awt/peer/gtk/GdkGraphics2D.java: Likewise.
* gnu/java/awt/peer/gtk/GdkGraphics.java: Likewise.
* gnu/java/awt/peer/gtk/GtkToolkit.java: Likewise.
* gnu/java/awt/peer/gtk/GdkTextLayout.java: Likewise.
Index: scripts/makemake.tcl
===================================================================
--- scripts/makemake.tcl (revision 114136)
+++ scripts/makemake.tcl (working copy)
@@ -49,7 +49,6 @@
set package_map(javax/imageio) bc
set package_map(javax/xml) bc
set package_map(gnu/java/beans) bc
-set package_map(gnu/java/awt/peer/gtk) bc
set package_map(gnu/java/awt/peer/qt) bc
set package_map(gnu/javax/sound/midi) bc
set package_map(org/xml) bc
@@ -258,8 +257,7 @@
# We skip these because they are built into their own libraries and
# are handled specially in Makefile.am.
- if {$loname != "gnu-java-awt-peer-gtk.lo"
- && $loname != "gnu-java-awt-peer-qt.lo"} {
+ if {$loname != "gnu-java-awt-peer-qt.lo"} {
lappend bc_objects $loname
}
}
Index: gnu/classpath/natSystemProperties.cc
===================================================================
--- gnu/classpath/natSystemProperties.cc (revision 114136)
+++ gnu/classpath/natSystemProperties.cc (working copy)
@@ -121,6 +121,26 @@
}
#endif
+// Prepend GCJ_VERSIONED_LIBDIR to a module search path stored in a
+// Java string, if the path is not already prefixed by
+// GCJ_VERSIONED_LIBDIR. Return a newly JvMalloc'd char buffer. The
+// result should be freed using JvFree. See
+// _Jv_PrependVersionedLibdir in prims.cc.
+static char*
+PrependVersionedLibdir (::java::lang::String* libpath)
+{
+ char* retval = 0;
+
+ // Extract a C char array from libpath.
+ char* val = (char*) _Jv_Malloc (JvGetStringUTFLength (libpath) + 1);
+ jsize total = JvGetStringUTFRegion (libpath, 0, libpath->length(), val);
+ val[total] = '\0';
+ retval = _Jv_PrependVersionedLibdir (val);
+ JvFree (val);
+
+ return retval;
+}
+
void
gnu::classpath::SystemProperties::insertSystemProperties (java::util::Properties *newprops)
{
@@ -288,8 +308,11 @@
SET ("user.region", "US");
}
- // The java extensions directory.
- SET ("java.ext.dirs", JAVA_EXT_DIRS);
+ // Set the java extension directories property if it has not yet been
+ // specified.
+ ::java::lang::String *extdirs = newprops->getProperty(JvNewStringLatin1("java.ext.dirs"));
+ if (! extdirs)
+ SET ("java.ext.dirs", JAVA_EXT_DIRS);
// The endorsed directories that libgcj knows about by default.
// This is a way to get other jars into the boot class loader
@@ -343,9 +366,9 @@
::java::lang::String *path = newprops->getProperty(JvNewStringLatin1("java.library.path"));
if (path)
{
- char *val = (char *) _Jv_Malloc (JvGetStringUTFLength (path) + 1);
- jsize total = JvGetStringUTFRegion (path, 0, path->length(), val);
- val[total] = '\0';
+ // Prepend GCJ_VERSIONED_LIBDIR to the module load path so that
+ // libgcj will find its own JNI libraries, like libgtkpeer.so.
+ char* val = PrependVersionedLibdir (path);
_Jv_SetDLLSearchPath (val);
_Jv_Free (val);
}
@@ -354,11 +377,10 @@
// Set a value for user code to see.
#ifdef USE_LTDL
char *libpath = getenv (LTDL_SHLIBPATH_VAR);
- if (libpath)
- newprops->put(JvNewStringLatin1 ("java.library.path"),
- JvNewStringLatin1 (libpath));
- else
- SET ("java.library.path", "");
+ char* val = _Jv_PrependVersionedLibdir (libpath);
+ SET ("java.library.path", val);
+ _Jv_SetDLLSearchPath (val);
+ _Jv_Free (val);
#else
SET ("java.library.path", "");
#endif
Index: configure.ac
===================================================================
--- configure.ac (revision 114136)
+++ configure.ac (working copy)
@@ -227,7 +227,6 @@
done
AM_CONDITIONAL(XLIB_AWT, test "$use_xlib_awt" = yes)
-AM_CONDITIONAL(GTK_AWT, test "$use_gtk_awt" = yes)
AM_CONDITIONAL(QT_AWT, test "$use_qt_awt" = yes)
# Create standard.omit based on decisions we just made.
Index: classpath/native/jni/gtk-peer/Makefile.am
===================================================================
--- classpath/native/jni/gtk-peer/Makefile.am (revision 114136)
+++ classpath/native/jni/gtk-peer/Makefile.am (working copy)
@@ -1,5 +1,8 @@
-## GCJ LOCAL: don't install this library
-noinst_LTLIBRARIES = libgtkpeer.la
+## GCJ LOCAL: install this library in GCJ's versioned library
+## directory
+gcc_version := $(shell cat $(top_srcdir)/../../gcc/BASE-VER)
+gcjversionedlibdir = $(libdir)/gcj-$(gcc_version)
+gcjversionedlib_LTLIBRARIES = libgtkpeer.la
# Gtk/Cairo JNI sources.
if GTK_CAIRO
@@ -52,6 +55,10 @@
gtk_jawt.c \
gtkpeer.h
+## GCJ LOCAL: encode the library path and use GCJ's library version
+libgtkpeer_la_LDFLAGS = -rpath $(gcjversionedlibdir) \
+ -version-info `grep -v '^\#' $(top_srcdir)/../libtool-version`
+
libgtkpeer_la_LIBADD = $(top_builddir)/native/jni/classpath/native_state.lo \
$(top_builddir)/native/jni/classpath/jcl.lo
Index: classpath/native/jawt/Makefile.am
===================================================================
--- classpath/native/jawt/Makefile.am (revision 114136)
+++ classpath/native/jawt/Makefile.am (working copy)
@@ -1,13 +1,16 @@
-## GCJ LOCAL: don't install this library
-noinst_LTLIBRARIES = libjawtgnu.la
+## GCJ LOCAL: install this library in GCJ's versioned library
+## directory
+gcc_version := $(shell cat $(top_srcdir)/../../gcc/BASE-VER)
+gcjversionedlibdir = $(libdir)/gcj-$(gcc_version)
+gcjversionedlib_LTLIBRARIES = libjawt.la
-libjawtgnu_la_SOURCES = jawt.c
-libjawtgnu_la_LIBADD = $(top_builddir)/native/jni/gtk-peer/libgtkpeer.la
-# FIXME: libtool doesn't allow overriding SONAME, but we need to set
-# it to libjawt.so for binary compatibility.
-#
-# libjawtgnu_la_LDFLAGS = -Wl,-soname -Wl,libjawt.so
+libjawt_la_SOURCES = jawt.c
+libjawt_la_LIBADD = $(top_builddir)/native/jni/gtk-peer/libgtkpeer.la
+## GCJ LOCAL: encode the library path and use GCJ's library version
+libjawt_la_LDFLAGS = -rpath $(gcjversionedlibdir) \
+ -version-info `grep -v '^\#' $(top_srcdir)/../libtool-version`
+
AM_LDFLAGS = @CLASSPATH_MODULE@ @GTK_LIBS@ @CAIRO_LIBS@ @PANGOFT2_LIBS@ @X_LIBS@ -lXtst
AM_CPPFLAGS = @CLASSPATH_INCLUDES@
Index: classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java
===================================================================
--- classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java (revision 114136)
+++ classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java (working copy)
@@ -62,10 +62,7 @@
static
{
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("gtkpeer");
- }
+ System.loadLibrary("gtkpeer");
initStaticState ();
Index: classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java
===================================================================
--- classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java (revision 114136)
+++ classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java (working copy)
@@ -75,10 +75,8 @@
{
static
{
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("gtkpeer");
- }
+ System.loadLibrary("gtkpeer");
+
initStaticState ();
}
Index: classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java
===================================================================
--- classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java (revision 114136)
+++ classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java (working copy)
@@ -104,8 +104,7 @@
throw new Error("Graphics2D not implemented. "
+ "Cairo was not found or disabled at configure time");
- if (Configuration.INIT_LOAD_LIBRARY)
- System.loadLibrary("gtkpeer");
+ System.loadLibrary("gtkpeer");
initStaticState();
}
Index: classpath/gnu/java/awt/peer/gtk/GdkGraphics.java
===================================================================
--- classpath/gnu/java/awt/peer/gtk/GdkGraphics.java (revision 114136)
+++ classpath/gnu/java/awt/peer/gtk/GdkGraphics.java (working copy)
@@ -56,10 +56,8 @@
{
static
{
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("gtkpeer");
- }
+ System.loadLibrary("gtkpeer");
+
initStaticState ();
}
Index: classpath/gnu/java/awt/peer/gtk/GtkToolkit.java
===================================================================
--- classpath/gnu/java/awt/peer/gtk/GtkToolkit.java (revision 114136)
+++ classpath/gnu/java/awt/peer/gtk/GtkToolkit.java (working copy)
@@ -107,8 +107,7 @@
static
{
- if (Configuration.INIT_LOAD_LIBRARY)
- System.loadLibrary("gtkpeer");
+ System.loadLibrary("gtkpeer");
int portableNativeSync;
String portNatSyncProp =
Index: classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java
===================================================================
--- classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java (revision 114136)
+++ classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java (working copy)
@@ -70,10 +70,8 @@
// native side, plumbing, etc.
static
{
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("gtkpeer");
- }
+ System.loadLibrary("gtkpeer");
+
initStaticState ();
}
private native void setText(String str);
Index: include/jvm.h
===================================================================
--- include/jvm.h (revision 114136)
+++ include/jvm.h (working copy)
@@ -660,4 +660,7 @@
return c->state == JV_STATE_PHANTOM;
}
+// A helper function defined in prims.cc.
+char* _Jv_PrependVersionedLibdir (char* libpath);
+
#endif /* __JAVA_JVM_H__ */
Index: gij.cc
===================================================================
--- gij.cc (revision 114136)
+++ gij.cc (working copy)
@@ -14,6 +14,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
static void
help ()
@@ -71,6 +72,47 @@
int
main (int argc, char const** argv)
{
+ // libjawt.so must be installed in GCJ's versioned directory and not
+ // the main library directory so that it doesn't override other
+ // libjawt.so implementations. Programs that use the AWT Native
+ // Interface contain a JNI library that links to libjawt.so. We do
+ // not want to require that users explicitly add GCJ's versioned
+ // directory to LD_LIBRARY_PATH when running such programs.
+
+ // Simply adding GCJ's versioned directory to the module load path
+ // does not solve this problem since libltdl searches its module
+ // load path only for object that it will dlopen; dependencies of
+ // these dynamically loaded objects are searched for in
+ // LD_LIBRARY_PATH.
+
+ // In addition, setting LD_LIBRARY_PATH from within the current
+ // process does not alter the dependency search path, since it is
+ // computed on startup. This behaviour makes sense since
+ // LD_LIBRARY_PATH is designed to allow users to override the path
+ // set by a program. This re-spawning trick makes it impossible to
+ // override, using LD_LIBRARY_PATH, the versioned directories
+ // searched by gij.
+
+ // Check if LD_LIBRARY_PATH is already prefixed with
+ // GCJ_VERSIONED_LIBDIR. If not, export LD_LIBRARY_PATH prefixed
+ // with GCJ_VERSIONED_LIBDIR and re-spawn gij.
+ char *libpath = getenv (LTDL_SHLIBPATH_VAR);
+ char *newpath = _Jv_PrependVersionedLibdir (libpath);
+
+ if (! libpath || strcmp (libpath, newpath))
+ {
+ setenv (LTDL_SHLIBPATH_VAR, newpath, 1);
+ JvFree (newpath);
+
+ int error_code = execv (GIJ_EXECUTABLE, (char* const*) argv);
+
+ fprintf (stderr, "error re-spawning gij with new "
+ LTDL_SHLIBPATH_VAR " value: %s\n", strerror (error_code));
+
+ return error_code;
+ }
+ JvFree (newpath);
+
JvVMInitArgs vm_args;
bool jar_mode = false;
Index: Makefile.am
===================================================================
--- Makefile.am (revision 114136)
+++ Makefile.am (working copy)
@@ -40,10 +40,6 @@
toolexeclib_LTLIBRARIES += lib-gnu-awt-xlib.la
endif
-if GTK_AWT
-toolexeclib_LTLIBRARIES += lib-gnu-java-awt-peer-gtk.la libgcjawt.la
-endif
-
if QT_AWT
toolexeclib_LTLIBRARIES += lib-gnu-java-awt-peer-qt.la
endif
@@ -128,6 +124,9 @@
-DBOOT_CLASS_PATH="\"$(BOOT_CLASS_PATH_DIR)\"" \
-DJAVA_EXT_DIRS="\"$(jardir)/ext\"" \
-DGCJ_ENDORSED_DIRS="\"$(jardir)/gcj-endorsed\"" \
+ -DGCJ_VERSIONED_LIBDIR="\"$(libdir)/gcj-$(gcc_version)\"" \
+ -DGIJ_EXECUTABLE="\"$(bindir)/gij$(EXEEXT)\"" \
+ -DPATH_SEPARATOR="\"$(CLASSPATH_SEPARATOR)\"" \
-DLIBGCJ_DEFAULT_DATABASE="\"$(dbexecdir)/$(db_name)\"" \
-DLIBGCJ_DEFAULT_DATABASE_PATH_TAIL="\"$(db_pathtail)\"" \
-DTOOLEXECLIBDIR="\"$(toolexeclibdir)\""
@@ -247,33 +246,6 @@
## not available.
./gcj-dbtool -n $(db_name) || touch $(db_name)
-## For the peer library, DEPENDENCIES need to come before OBJECTS so
-## that JNI headers are built before JNI C files.
-$(lib_gnu_java_awt_peer_gtk_la_OBJECTS): $(lib_gnu_java_awt_peer_gtk_la_DEPENDENCIES)
-
-lib_gnu_java_awt_peer_gtk_la_SOURCES =
-lib_gnu_java_awt_peer_gtk_la_LIBADD = \
- gnu-java-awt-peer-gtk.lo \
- classpath/native/jni/gtk-peer/libgtkpeer.la \
- $(GTK_LIBS) $(GLIB_LIBS) $(LIBART_LIBS) $(CAIRO_LIBS) $(PANGOFT2_LIBS)
-lib_gnu_java_awt_peer_gtk_la_DEPENDENCIES = gnu-java-awt-peer-gtk.lo \
- classpath/native/jni/gtk-peer/libgtkpeer.la \
- libgcj-$(gcc_version).jar libgcj.la libgcj.spec
-## The mysterious backslash in the grep pattern is consumed by make.
-lib_gnu_java_awt_peer_gtk_la_LDFLAGS = \
- -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) $(X_LIBS) -lXtst
-lib_gnu_java_awt_peer_gtk_la_LINK = $(LIBLINK)
-
-libgcjawt_la_SOURCES = classpath/native/jawt/jawt.c
-libgcjawt_la_CFLAGS = -I$(srcdir)/classpath/native/jni/classpath \
- $(PEDANTIC_CFLAGS) $(X_CFLAGS)
-## See jv_convert_LDADD.
-libgcjawt_la_LIBADD = -L$(here)/.libs lib-gnu-java-awt-peer-gtk.la
-libgcjawt_la_LDFLAGS = \
- -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
- $(LIBGCJ_LD_SYMBOLIC)
-libgcjawt_la_LINK = $(LIBLINK)
-
lib_gnu_java_awt_peer_qt_la_SOURCES =
lib_gnu_java_awt_peer_qt_la_LIBADD = \
gnu-java-awt-peer-qt.lo \
@@ -347,6 +319,10 @@
%.lo: %.list
$(LTGCJCOMPILE) -c -o $@ -MT $@ -MD -MP -MF $(basename $@).deps @$<
+## Specify -fjni for GTK peers.
+gnu-java-awt-peer-gtk.lo: gnu/java/awt/peer/gtk.list
+ $(LTGCJCOMPILE) -fjni -c -o $@ -MT $@ -MD -MP -MF $(basename $@).deps @$<
+
## ################################################################
## This pulls in a number of variable and target definitions.
Index: prims.cc
===================================================================
--- prims.cc (revision 114136)
+++ prims.cc (working copy)
@@ -1723,3 +1723,45 @@
&& _Jv_ClassNameSamePackage (self_klass->name,
other_klass->name)));
}
+
+// Prepend GCJ_VERSIONED_LIBDIR to a module search path stored in a C
+// char array, if the path is not already prefixed by
+// GCJ_VERSIONED_LIBDIR. Return a newly JvMalloc'd char buffer. The
+// result should be freed using JvFree.
+char*
+_Jv_PrependVersionedLibdir (char* libpath)
+{
+ char* retval = 0;
+
+ if (libpath && libpath[0] != '\0')
+ {
+ if (! strncmp (libpath,
+ GCJ_VERSIONED_LIBDIR,
+ sizeof (GCJ_VERSIONED_LIBDIR) - 1))
+ {
+ // LD_LIBRARY_PATH is already prefixed with
+ // GCJ_VERSIONED_LIBDIR.
+ retval = (char*) _Jv_Malloc (strlen (libpath) + 1);
+ strcpy (retval, libpath);
+ }
+ else
+ {
+ // LD_LIBRARY_PATH is not prefixed with
+ // GCJ_VERSIONED_LIBDIR.
+ jsize total = (sizeof (GCJ_VERSIONED_LIBDIR) - 1)
+ + (sizeof (PATH_SEPARATOR) - 1) + strlen (libpath) + 1;
+ retval = (char*) _Jv_Malloc (total);
+ strcpy (retval, GCJ_VERSIONED_LIBDIR);
+ strcat (retval, PATH_SEPARATOR);
+ strcat (retval, libpath);
+ }
+ }
+ else
+ {
+ // LD_LIBRARY_PATH was not specified or is empty.
+ retval = (char*) _Jv_Malloc (sizeof (GCJ_VERSIONED_LIBDIR));
+ strcpy (retval, GCJ_VERSIONED_LIBDIR);
+ }
+
+ return retval;
+}