java library installation issues

Per Bothner
Tue Apr 3 08:58:00 GMT 2001 (Andrew Pimlott) writes:

> What recommendation should we make to packagers of libraries that
> have native components?  I assume that Java native method APIs (like
> JNI) are source-level, not binary-level.

JNI is binary-level, in the sense that compiled JNI code should
be independent of Java implementation.  Gcj also supports "CNI"
which is loosely using C++ to access Java objects in a very
natural and efficient way.  CNI is tied to the Java implementation,
and is only portable at the source-level.  (Currently it is
specific to gcj.)

> Thus one should expect
> compiled native code libraries to work on only one implementation,
> right?

true for CNI libraries, false for JNI libraries.

> In that case, should we recommend that packagers compile
> such libraries against as many implementations as feasible?

Not needed.  If native code is written using JNI it should be portable
to all Java implementation that ise JNI (including gcj).

If a library is compiled to native code using gcj, then the resulting
shared library should (in my opinion) contain both the compiled Java
code and the native code.  That is what we do for CNI; it may be reasonable
to also do that for JNI.  In that case, the JNI code would probably
*also* be in a portable shaerd library (without the compiled Java code).

> On the other hand, if JNI is an ABI, it would
> be nice to put compiled libraries somewhere where they would be
> found by all compatible implementations.

JNI libraries shold probably (by default) go in either /usr/lib
or /usr/lib/java.  The latter again has the advantage of reducing
clutter and name clashes, but I don't know how awkward that would
be for other Java implementations.

> > So to summarize:  The builtin search path should be (in this order):
> > (1) each .jar file in /usr/share/java/$implementation
> > (2) each .jar file in /usr/share/java
> > (3) the /usr/share/java directory itself
> This is plausible for the VM (but see below), but not the compiler.
> To my understanding, the compiler should not need to see the native
> parts of libraries to compile against them; the .class files should
> be sufficient.  But having the compiler search all of the
> $implementation directories doesn't seem right.

Each compiler would only search a single /usr/share/java/$implementation
directory for jars.  I.e. gcj would add /usr/share/java/gcj/*.jar and
/usr/share/java/*.jar to the path; kaffe would add
/usr/share/java/kaffe/*.jar and /usr/share/java/*.jar, etc.  Jikes
(which doesn't have its own libraries) needs to pick one, perhaps
using the /etc/alternatives mechanism.

> Perhaps a
> /usr/share/java/compiler or /usr/share/java/include directory
> containing just "header" files--ie, skeleton .class files--for
> libraries with native components?

Er, .class files *are* skeleton .class files.  No head for header

> At very least, there needs to be a way for compilers not associated
> with a particular java implementation (eg jikes) to find the
> standard libraries.

That's my point:  There is no "standard" set of standard libraries.
The standard libraries of jdk, kaffe, and gcj are all different.
Jikes can work with any of them.  Putting a symlink from
/usr/share/java/jdk1.3 (say) to /usr/share/java/jikes is one
solution, assuming jdk1.3 is installed.  Better might be for
jikes to get installed as a shell script wrapper that picks
an available set of libraries.

> > I've left out versioning issues.  If one want to support multiple
> > versions of the same library one could install LIBRARY-VERSION.jar,
> > and install a symlink from LIBRARY.jar, but having compilers and
> > VMs pick the right version is unclear to me.
> This immediately points out a serious drawback to putting
> /usr/share/java/*.jar in the classpath automatically.  Another
> drawback is the existence of multiple implementations of some APIs.
> I conclude that we should not not automatically put *.jar in the
> classpath.  In C, the user specifies which libraries he wants to use
> at compile time,

But the *default* is to search /usr/include at compile-time, and to
link with glibc.  I want the default experience to be simple.
In Java we have a global namespace, so the user/developer should not
have to specify classpaths etc by default.  Of course it should be
possible to override classpaths to pick up specific versions, but
it is more important that the default be easy.

One idea is that /usr/share/java (and /usr/share/java/$implementation)
can contain multiple versions of a library, and a compiler should
serach the appropriate one.  A rough algorith:  Sort the list of
*.jar files names.  If there is both a XXX.jar and one or more XXX-NNN.jar,
pick XXX.jar.  Typically XXX.jar will be a symlink t teh "preferred"
version.  Similarly, if there are XXX-MM.jar and one or more XXX-MM-NN.jar,
pick XXX-MM.jar.

Note this would only be for the *builtin* search path.  Someone
could always explicitly put /usr/share/java/XXX-MM.jar earlier in the
search path.  So I think this combines convenience with flexibility.

> and the executable declares the libraries
> (including versions) it wants to use at run-time.  What is wrong
> with this model for Java?

That's what I'm proposing.  I just don't want the user to have to
specify lots of mysterious -lLIBRARY flags to gcj.

> Java executables should, in general, be
> wrappers (probably shell scripts) that specify the needed libraries
> in an implementation-independent way, then run something like "java
> -Dfoo=bar class".  All implementations should take the list of
> needed libraries from the wrapper, plus user-overrides (which should
> also be specified in an implementation-independent way), and try to
> run.  Of course, the implementation for which the user has "java"
> selected by his $PATH is the one that should be used.

When compiling a Java application to native code, the executable should
preferably be a native program.  Requiring an extra shell wrapper
is just extra clutter and overhead.
	--Per Bothner

More information about the Java mailing list