I have actualised the sample given on IDEA website's guide on JNI in this repo (you can see fork there) and now it runs with modern JDK and JUnit Tests even on my aarch64 Mac (hope it runs anywhere else). But I do not really understand what is going on in build.gradle
in hello
Gradle subproject folder. I can recognise compiler arguments there, but include options are set in separate methods, which gets me confused.
My aim is to have just wrapper C-file that doing dlopen
(or its Windows' alternative) and runs some function from dynamic library.
E.g.
<ProjectRoot>/hello/src/main/c/ wrapper-with-JNI-call-convensions.c
libsomelib.dylib
libsomelib.so
somelib.dll
Calls looks like this: Java -[JNI]-> wrapper.dll -> somelib.dll
^ ^ ^
| | |
building wrapper.c using Gradle to this
So I have successfully managed to get JNI working (while not changing build.gradle
from sample) if I just run build with two C source files (wrapper that uses JNI and C source code of my library). Then I built dylib
using macOS built-in clang
compiler and wrote proper (I guess) dlopen
and dlsym
code. But when I build project I get NULL returned from dlopen
call.
I have tried to add some arguments to the build.gradle
that used to compile binary that uses dynamic library, but it did not help.
My test running exits here:
// my wrapper
void* dlHandle = dlopen("libsomelib.dylib", RTLD_LAZY);
if (dlHandle == NULL) {
printf("DLL NOT OPENED !!!\n");
exit(0);
}
I know I have to write proper platform-dependent calls in my wrapper, it's not a big deal for me.
So can you tell me how I can properly get this working using Gradle? Remember that goal is to have just JNI-ready *.c
wrapper and just dynamic linked libraries *.so & *.dylib & *.dll
in my case.
CodePudding user response:
To get it running you can try following:
> cc -g -shared -fpic wrapper.c -L. -lsome -o libwrapper.dylib
I assume that you have libsome.dylib
inside current directory. Then you can load libwrapper.dylib
inside JNI
and it refer to this another lib: libsome.dylib
Update
Let's say you have these two files:
#include <stdio.h>
void anotherFunction () {
// we are printing message from another C file
printf ("Hello from another function!\n");
}
and corresponding header file
#ifndef another_h__
#define another_h__
void anotherFunction (void)
#endif // another_h__
You can build a library out of it, by calling something like this:
cc -shared -fpic recipeNo023_AnotherFunction.c -o libanother.dylib
This will be equivalent of your: somelib
Then, we can have something like this:
#include "recipeNo023_redux_HelloWorld.h"
void anotherFunction ();
JNIEXPORT void JNICALL Java_recipeNo023_redux_HelloWorld_displayMessage
(JNIEnv * env, jclass obj) {
printf ("Hello world!\n");
/* We are calling function from another source */
anotherFunction ();
}
We declare function and use it. Name will be resolved later, during linking phase.
Now, you can compile your wrapper
lib. In this sample it's HelloWorld
.
cc -shared -fpic recipeNo023_redux_HelloWorld.c -L. -lanother
Now, inside JNI
, all you do is:
System.loadLibrary("HelloWorld");
Due to the fact HelloWorld
was linked with shared library another
it will have access to its symbols. So, you don't need to use dlopen
.
Try the sample (there is even Docker based file so you don't have to struggle with setting up environment).