views:

251

answers:

3

I have written an application in Java and succesfully compiled it using gcj. It worked surprisingly well, but I've run into a hurdle: I can only run the executable through a shell script, because I have to specify the library paths.

The libraries I need are SWT, Xerces and GNU-crypto.

Is there a way to statically link the libraries when compiling in gcj, or is this not a good idea? Alternatively, can I specify the (relative) library path while compiling?

Presently, my shell script looks like this:

#!/bin/sh
export LD_LIBRARY_PATH=./libs/:$LD_LIBRARY_PATH
exec ./MyJavaApp $*
A: 

To answer the first part of your question -

From the gcj man page: "Static linking of libgcj may cause essential parts of libgcj to be omitted. Some parts of libgcj use reflection to load classes at runtime. Since the linker does not see these references at link time, it can omit the referred to classes. The result is usually (but not always) a "ClassNotFoundException" being thrown at runtime. Caution must be used when using this option."

For the static linking of the other libraries, I'm not sure. I haven't had a reason to do that.

Linux executables are different than Windows. Normally you have a "launcher" or some such depending on which exact windowing system you are using. You set the icon in that, not on the executable itself. Usually, launch scripts are used to set any environment that you need for running the executable. Again, this all depends on your exact desktop window system.

darelf
So static linking is perhaps not the best approach. Is there some standard way of specifying shared libraries? Using a `make install` comes to mind.
Paul Lammertsma
I've split the question; the part concerning icons can now be found here: http://stackoverflow.com/questions/2126545/embedding-an-icon-in-a-linux-executable
Paul Lammertsma
A: 

Why are you using an AOT? I would suggest reading the following article. One of the drawbacks that it mentions for AOTs is the following...

Dynamic applications. Classes that the application loads dynamically at runtime may be unavailable to the application developer. These can be third-party plug-ins, dynamic proxies and other classes generated at runtime and so on. So the runtime system has to include a Java bytecode interpreter and/or a JIT compiler.

prometheus
I'm afraid that choice isn't mine to make. Yes, using the interpreter would be easier, but I need to provide an executable in native code.
Paul Lammertsma
Ah, I see that you found the answer to your first question right here? http://stackoverflow.com/questions/1171525/why-doesnt-gcj-find-the-classes-from-my-imported-packages
prometheus
Well, not really. I compile the libraries like I demonstrated in my answer, but I can't figure out a way to have them found when running the executable aside from changing the library path in a shell script. It feels clumsy and there must be a neater solution.
Paul Lammertsma
+3  A: 

The idea is to make the static field "sys_paths" null so that it would construct the paths from the changed value. See the post here (Post#223 by AjaySingh516) http://forums.sun.com/thread.jspa?messageID=3744346#3744346

Class clazz = ClassLoader.class;
Field field = clazz.getDeclaredField("sys_paths");
boolean accessible = field.isAccessible();
if (!accessible)
    field.setAccessible(true);
Object original = field.get(clazz);
// Reset it to null so that whenever "System.loadLibrary" is called, it
// will be reconstructed with the changed value.
field.set(clazz, null);
try {
    // Change the value and load the library.
    System.setProperty("java.library.path", "./libs/");
    System.loadLibrary("mylibapr");
} finally {
    // Revert back the changes.
    field.set(clazz, original);
    field.setAccessible(accessible);
}

.

gcj System Properties (See: Standard properties supported by libgcj)

http://gcc.gnu.org/onlinedocs/gcj/System-properties.html

.

Solution#2 : Set System environment variable at compile time

http://linux.die.net/man/1/gcj

For this you have to use parameter -Djava.library.path=./libs/ with gcj

From gcj manual (above link):

--main= CLASSNAME

This option is used when linking to specify the name of the class whose "main" method should be invoked when the resulting executable is run.

-Dname[=value]

This option can only be used with "--main". It defines a system property named name with value value. If value is not specified then it defaults to the empty string. These system properties are initialized at the program's startup and can be retrieved at runtime using the "java.lang.System.getProperty" method.

I have never worked with gcj but as per docs these system properties can be retrieved at runtime, hence it will be portable to other systems as well.

Also see: http://gcc.gnu.org/wiki/Statically_linking_libgcj?action=show&redirect=Statically+linking+libgcj

Gladwin Burboz
You can have "./libs/" and "mylibapr" passed in as command line parameter.
Gladwin Burboz
This seems very promising; I'll take a look tomorrow morning!
Paul Lammertsma
@Paul: Want to keep you informed that this solution may be JVM specific and hence won't be super portable. Here we are playing with private variable of class ClassLoader. This Open JDK ClassLoader source code has it "http://www.docjar.com/html/api/java/lang/ClassLoader.java.html"
Gladwin Burboz
Does setting the environment variable with `-Djava.library.path` only affect my local machine, or will it set the library path for the executable on any Linux machine I run it from?
Paul Lammertsma
@Paul: Did it help? Updated solution with extra info "These system properties are initialized at the program's startup and can be retrieved at runtime".
Gladwin Burboz
I'm looking into implementing solution #2 at this very moment. I'll keep you posted.
Paul Lammertsma
Updating `gcj` to 4.4 is giving me all sorts of problems that I can't sort out before the bounty expires. I'm going to mark this as the accepted answer as has pointed me in the right direction, if not solved the problem altogether. I will update the OP when I resolve it to satisfaction.
Paul Lammertsma
If your project is really big, I would recommend you to create a proof of concept "hello world app" to try this solutions . Less complexity will help you focus on problem at hand and get rid of may other issues. Let us know it worked.
Gladwin Burboz