Avian embedded on a shared library

40 views
Skip to first unread message

Evandro Rathke

unread,
Jul 7, 2017, 2:14:03 PM7/7/17
to Avian
Hi everyone!

I'm trying to embed Avian on a shared library which will be loaded by another application.
When I build the shared library as a executable (just creating a main function), everything works fine. But when the another application loads the shared library, the "JNIEnv->findClass" always return "Class not found" message, even for "java/lang/Class" for example. 
The JVM is being instantiated successfully, but apparently the JNIEnv doesn't works. 

I'm generating the shared library using "-shared" option instead of the "-rdynamic".

I tried as well to attach the JNIEnv to the current thread when the application calls the function, which have the "findClass" error, but unsuccessfully.

Thanks in advance.
Evandro

Joel Dice .

unread,
Jul 8, 2017, 12:53:00 PM7/8/17
to Avian, era...@gmail.com
Hi Evandro,

You may need to pass the "avian.bootstrap" property to the VM,
specifying the name of the shared library. That tells Avian where to
do dynamic lookups for classes, JNI methods, etc. See src/main.cpp
for an example.

If that doesn't help, please provide a test case so I can reproduce
the problem and debug it.

Cheers,
Joel
> --
> You received this message because you are subscribed to the Google Groups
> "Avian" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to avian+un...@googlegroups.com.
> To post to this group, send email to av...@googlegroups.com.
> Visit this group at https://groups.google.com/group/avian.
> For more options, visit https://groups.google.com/d/optout.

Evandro Rathke

unread,
Jul 8, 2017, 11:17:05 PM7/8/17
to Avian, era...@gmail.com
Hi Joel!

I tried again with your tips but the error persists.

Below is the relevant code of my implementation.

The additional library I'm using is lua-5.1.5, so the code needs:
  1. Includes: #include lua.hpp
  2. Compile with -llua option.  
Well, the code:

static int openVM(lua_State* state) {

// Initialising VM options

JavaVMInitArgs vmArgs;

vmArgs.version = JNI_VERSION_1_2;


vmArgs.nOptions = 2;

vmArgs.ignoreUnrecognized = JNI_TRUE;

// Build options array

JavaVMOption options[vmArgs.nOptions];

vmArgs.options = options;

options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");

char *optbootstrap = const_cast<char*>("-Davian.bootstrap=/tmp/libavian.dylib");

options[1].optionString = optbootstrap;

printf("Option: %s\n", optbootstrap);


// Creates JVM

JavaVM* vm;

void* env;

JNI_CreateJavaVM(&vm, &env, &vmArgs);

JNIEnv* e = static_cast<JNIEnv*>(env);


int exitCode = 0;

jclass c = e->FindClass("java/lang/Class");

if (e->ExceptionCheck()) {

exitCode = -1;

e->ExceptionDescribe();

}


vm->DestroyJavaVM();

return exitCode;

};


extern "C" int luaopen_avian(lua_State* state) {

printf("luaopen_avian(lua_State* state)\n");

openVM(state);

return 0;

}


To test on Lua, you need to do the steps below:
  1. Go to the directory where the shared library was created;
  2. Create a link: ln -s libavian.dylib avian.so
  3. Run the lua command loading the library: lua -l avian
If everything works, Lua will open the library calling luaopen_avian function.

Please, let me know it you need any help to produce the steps above.

Thanks in advance!
Evandro.

Joel Dice .

unread,
Jul 11, 2017, 12:10:01 PM7/11/17
to Avian, Evandro Rathke
Hi Evandro,

Based on the code you provided, it looks like you've used
https://github.com/ReadyTalk/avian#embedding as a starting point.
However, you left out an important part:

extern "C" {

extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];

EXPORT const uint8_t*
bootJar(size_t* size)
{
*size = SYMBOL(end) - SYMBOL(start);
return SYMBOL(start);
}

} // extern "C"

That ensures there is a bootJar function from which Avian can load the
boot jar. That's what makes this line work:

options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");

I've modified your code as follows:

#include "stdint.h"
#include "jni.h"
#include "stdlib.h"
#include "lua.hpp"

#define EXPORT __attribute__ ((visibility("default"))) \
__attribute__ ((used))

#define SYMBOL(x) _binary_boot_jar_##x

extern "C" {
extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];

EXPORT const uint8_t*
bootJar(size_t* size)
{
*size = SYMBOL(end) - SYMBOL(start);

return SYMBOL(start);
}
} // extern "C"

extern "C" void __cxa_pure_virtual(void) { abort(); }

namespace {

int openVM(lua_State* state) {

// Initialising VM options

JavaVMInitArgs vmArgs;

vmArgs.version = JNI_VERSION_1_2;

vmArgs.nOptions = 2;

vmArgs.ignoreUnrecognized = JNI_TRUE;

// Build options array

JavaVMOption options[vmArgs.nOptions];

vmArgs.options = options;

options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");

char *optbootstrap = const_cast<char*>("-Davian.bootstrap=avian.so");

options[1].optionString = optbootstrap;

printf("Option: %s\n", optbootstrap);

// Creates JVM
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);

JNIEnv* e = static_cast<JNIEnv*>(env);

int exitCode = 0;

{
jclass c = e->FindClass("java/lang/Class");
}

jclass c = e->FindClass("Hello");
if (not e->ExceptionCheck()) {
jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V");
if (not e->ExceptionCheck()) {
jclass stringClass = e->FindClass("java/lang/String");
if (not e->ExceptionCheck()) {
jobjectArray a = e->NewObjectArray(0, stringClass, 0);

if (not e->ExceptionCheck()) {
e->CallStaticVoidMethod(c, m, a);
}
}
}
}

if (e->ExceptionCheck()) {

exitCode = -1;

e->ExceptionDescribe();
} else {
printf("success!");
}

vm->DestroyJavaVM();

return exitCode;

}

} // namespace

extern "C" int luaopen_avian(lua_State* state) {
printf("luaopen_avian(lua_State* state)\n");

openVM(state);

return 0;
}

(I put that in a file called main.cpp)

Then I built everything like this:

ar x ~/p/avian/build/macosx-x86_64/libavian.a
cp ~/p/avian/build/macosx-x86_64/classpath.jar boot.jar
cat >Hello.java <<EOF
public class Hello {
public static void main(String[] args) {
System.out.println("hello, world!");
}
}
EOF
javac -bootclasspath boot.jar Hello.java
jar u0f boot.jar Hello.class
~/p/avian/build/macosx-x86_64/binaryToObject/binaryToObject boot.jar
boot-jar.o _binary_boot_jar_start _binary_boot_jar_end macosx x86_64
g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -I
/Users/dicej/Downloads/lua-5.1.5/etc/ -I
/Users/dicej/Downloads/lua-5.1.5/src/ -D_JNI_IMPLEMENTATION_ -c
main.cpp -o main.o
g++ -shared *.o -ldl -lpthread -lz -o avian.so -framework CoreFoundation

Then I ran it, and it seemed to work:

~/Downloads/lua-5.1.5/src/lua -l avian

Evandro Rathke

unread,
Jul 11, 2017, 2:53:51 PM7/11/17
to Avian, era...@gmail.com
Hi Joel!

I ran your example and it works!!!
I will compare with my code and adjust it.

Thank you very much! I really appreciate your help.
Evandro. 
Reply all
Reply to author
Forward
0 new messages