JNI exits with "undefined symbol" - java

I'm trying to use AES via the Crypto++ package from Java. Therefore I have two native methods encrypt and decrypt in my Java code which are then wrapped by C in order to access the C++ methods.
Running my C++ program from the command line works, but calling it from Java via JNI fails with an undefined symbol error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/yves/temp/lib/libCI3CppEncryptionTools.so: /home/yves/temp/lib/libCI3CppEncryptionTools.so: undefined symbol: _ZTIN8CryptoPP6FilterE
I'm compiling it via:
g++ -c -Icryptopp562 -O3 -fwhole-program -fdata-sections -ffunction-sections -fPIC -fpermissive CI3CppEncryptionToolsImpl.cpp -Lcryptopp562 -lcryptopp
gcc -I${JAVA_HOME}/include -O3 -fwhole-program -fdata-sections -ffunction-sections -Wall -shared -fPIC -o libCI3CppEncryptionTools.so CI3CppEncryptionTools.c CI3CppEncryptionToolsImpl.o -Wl,--gc-sections
So first the C++ part and then combined with the C wrapper. -fdata-sections, -ffunction-sections and -Wl,--gc-sections were my attempt to strip dead code because I thought maybe JNI does not like unused or unreferenced code.
I checked if the symbol is undefined by using:
nm lib/libCI3CppEncryptionTools.so | grep _ZTIN8CryptoPP6FilterE
U _ZTIN8CryptoPP6FilterE
And yes, it is. But why is my C++ command line program working? Checking this yields the same result.
I also looked the symbol up:
c++filt _ZTIN8CryptoPP6FilterE
typeinfo for CryptoPP::Filter
The header for CryptoPP::Filter is included. I'm curious why it says U when checking for the symbol.
Does anyone have any idea what could cause the problem or where to look next to solve the problem? Any hints/insights are highly welcome!

Compile your CI3CppEncryptionTools.c first, then link its .o into the .so. You are linking the .c
Edit: Statically link your cryptocpp library into your shared library via : -Wl,--whole-archive libcryptocpp.a -Wl,--no-whole-archive
gcc -I${JAVA_HOME}/include -O3 -fwhole-program -fdata-sections -ffunction-sections -Wall -shared -fPIC -o libCI3CppEncryptionTools.so CI3CppEncryptionTools.c CI3CppEncryptionToolsImpl.o -Wl,--whole-archive libcryptocpp.a -Wl,--no-whole-archive -Wl,--gc-sections

I always forgot to link the Crypto++ library in the second step (actually I did it in the first step, which was complete nonsense). Those two commands compile the library a-ok!
g++ -c -Icryptopp562 -O3 -fPIC -fpermissive CI3CppEncryptionToolsImpl.cpp
gcc -I${JAVA_HOME}/include -O3 -shared -fPIC -o libCI3CppEncryptionTools.so CI3CppEncryptionTools.c CI3CppEncryptionToolsImpl.o -lcryptopp

Related

Swig C++ to Java UnsatisfiedLinkError

I convert C++ to Java using swig.
I use g++ for creating DLL and compiling.
swig -c++ -java -package preprocessor Point.i
g++ -c -std=c++11 Point.cpp Point_wrap.cxx -I E:\ProgramFiles\jdk\include -I E:\ProgramFiles\jdk\include\win32
g++ -shared Point_wrap.o Point.o -o point.dll
I don't have any errors while compilation and creating dll.
So when I put generated java files and dll to my project I have an UnsatisfiedLinkError when I create new object. It appears only when I use Windows 8.1 x86. On x64 version everything works fine.
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: preprocessor.PointClassJNI.new_Point__SWIG_0()J
at preprocessor.PointClassJNI.new_Point__SWIG_0(Native Method)
at preprocessor.Point.<init>(Point.java:78)
at GUI.FileWorker.fileParser(FileWorker.java:45)
at GUI.MainWindow$2.actionPerformed(MainWindow.java:139)
This is what swig generates and where error occurs when I create point = new Point();
public Point() {
this(PointClassJNI.new_Point__SWIG_0(), true);
}
Maybe someone had this problem. I will be very grateful for any help!
Finally I find the solution in this question.
Just need to add -Wl,--add-stdcall-alias to my .bat file when I create dll.
swig -c++ -java -package preprocessor Point.i
g++ -c -std=c++11 Point.cpp Point_wrap.cxx -I E:\ProgramFiles\jdk\include -I E:\ProgramFiles\jdk\include\win32
g++ -shared Point_wrap.o Point.o -Wl,--add-stdcall-alias -o point.dll
rkapl, thank you for respond!

Calling Haskell from Java, dynamic linking error Relocation

I'm having troubles with compiling a standalone library for use by Java (with C++ inbetween).
There is a program in Haskell exporting one function that processes some text and returns it.
The program in Haskell needs some external data (binary file). I'm 'compiling it in' with the help of file-embed package.
When I started the compilation with:
$ ghc -fPIC -dynamic -c -O --make MyModule.hs
It throws the error:
MyModule.hs:239:15:
Dynamic linking required, but this is a non-standard build (eg. prof).
You need to build the program twice: once the normal way, and then
in the desired way using -osuf to set the object file suffix.
This is the place where I use file-embed.
So I tried the proposed approach (compiling twice, changing suffixes):
$ ghc -fPIC -c -O --make MyModule.hs
$ ghc -osuf d.o -fPIC -dynamic -c -O --make MyModule.hs
$ javac -cp javacpp.jar MyModule.java
$java -jar javacpp.jar -Dcompiler.path=ghc -Dcompiler.output.prefix="-optc-O3 -Wall MyModule.d.o -dynamic -fPIC -shared -lstdc++ -lHSrts-ghc7.6.3 -o " -Dcompiler.linkpath.prefix2="-optl -Wl,-rpath," MyModule
And now I'm getting an error that I don't understand:
/usr/bin/ld: MyModule.d.o: relocation R_X86_64_PC32 against undefined symbol `{Directory_with_code}zi{Some_module}_{Some_module}_con_info' can not be used when making a shared object; recompile with -fPIC
Can anyone explain it to me and give some tips on how to solve it?
Just a guess, but maybe you need to different version of HSrts-ghc-7.6.3 since this is a "non-standard" build.

Compiling SWIG java library with mingw

I've got a Java project which depends on a native library. I'm using SWIG to build the native library, which works fine on *nix systems. I'm trying to get it to compile now on Windows using the mingw 64 bit toolchain and SWIG. It will compile and I can get the jnilib packaged appropriately (i.e. the same way as I'm doing it on other platforms) but when I try to load the library in the Java code I get:
Exception in thread "main" java.lang.UnsatisfiedLinkError: ... .jnilib: Can't find dependent libraries
and then it has the trace on the java side. Clearly I'm not linking something properly but I'm not sure what. Here's the relevant part of my compile commands:
swig -java -package cStopPow -c++ StopPow.i
x86_64-w64-mingw32-g++ -I"C:/Progra~1/Java/jdk1.7.0_25/include/" -I"C:/Progra~1/Java/jdk1.7.0_25/include/win32/" -std=c+
+11 -O3 -I"C:/MinGW/include/boost/math/" -c ../src/StopPow.cpp ../src/StopPow_SRIM.cpp ../src/StopPow_LP.cpp ../src/Stop
Pow_BetheBloch.cpp ../src/StopPow_AZ.cpp ../src/PlotGen.cpp ../src/AtomicData.cpp StopPow_wrap.cxx
x86_64-w64-mingw32-g++ -shared -lmingw32 -mconsole StopPow_wrap.o StopPow.o StopPow_SRIM.o StopPow_LP.o StopPow_BetheBlo
ch.o StopPow_AZ.o PlotGen.o AtomicData.o -o libcStopPow.jnilib
Why the output is libcStopPow.jnilib? I think it must a dll file
I use SWIG 2.0.10, Oracle JDK 1.7.0_40 and mingw 64 from http://nuwen.net/ with the Examples\java\simple. I do the following in cmd (I set JAVA_HOME correctly)
swig -java -c++ example.i
g++ -Wall -Wl,--kill-at -I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" -shared -s -o example.dll *.c *.cxx
java -cp . runme
It works as expected

SWIG CYGWIN DLL linking

I'm trying to follow the SWIG Java example located here. This example uses cygwin for compilation. I would like to pass the compiler an alredy compiled dll, test.dll, instead of a C source file. The SWIG.org example uses C source. I attempted to pass the test.dll(compiled C source) and then example.dll to the 3rd command but I get an error "test.dll: no such file or directory". The SWIG.org example's 3rd command creates the example.dll based on example.c. How can I create example.dll so that it uses test.dll instead of example.c?
Is there a way to accomplish this within the context of this example?
My Attempt without C Source, just dll:
$ swig -java example.i
$ gcc example_wrap.c -I/c/jdk1.6.0_30/include -I/c/jdk1.6.0_30/include/win32
$ gcc -shared example_wrap.o -mno-cygwin -Wl,--add-stdcall-alias -o test.dll example.dll
SWIG.org Example Code:
$ swig -java example.i
$ gcc **-c example.c** example_wrap.c -I/c/jdk1.3.1/include -I/c/jdk1.3.1/include/win32
$ gcc -shared example.o example_wrap.o -mno-cygwin -Wl,--add-stdcall-alias -o example.dll
You need to pass test.dll to the last command, which links your program, rather than the second, which just compiles the example_wrap.c source file. (The -c option tells gcc to compile only.)
Note that the ordering of objects and DLLs on the link line is important. DLLs should come after anything that uses them.

Cross-compiling for PPC G3 with MacOS 10.3.9

I am writing a program to talk to a USB hardware interface board, which requires a small JNI library. I am running 10.5.8 on my compile machine, and can succesfully compile the shared library for JNI with the following commands:
# Build shared library for K8055
g++ -x objective-c -fmessage-length=0 -pipe -Wno-trigraphs \
-fpascal-strings -fasm-blocks -O0 -mdynamic-no-pic -fvisibility=hidden -gdwarf-2 \
-Wmost -Wno-four-char-constants -Wno-unknown-pragmas \
-c ./K8055/K8055.m \
-o ./K8055/K8055.o \
-arch x86_64 \
-arch i386
echo "Building JNI shared library..."
gcc -c -m64 -I/System/Library/Frameworks/JavaVM.framework/Headers \
k8055usbio.m -o k8055usbio.so -arch x86_64
echo "Compiling dynamic library with both..."
g++ -m64 -dynamiclib -o ./lib/libk8055usbio.dylib \
k8055usbio.so ./K8055/K8055.o\
-framework Foundation -framework IOKit
I don't really understand what I'm doing here; I have managed to piece that together from a lot of Googling. My question is: How do I modify this to compile for a PPC G3 machine running 10.3.9? The Java part I am happy with. Here is what I've tried so far:
# Build shared library for K8055 (PPC)
echo "Building driver shared library..."
g++ -x objective-c -fmessage-length=0 -pipe -Wno-trigraphs \
-fpascal-strings -fasm-blocks -O0 -mdynamic-no-pic -fvisibility=hidden -gdwarf-2 \
-Wmost -Wno-four-char-constants -Wno-unknown-pragmas \
-c ./K8055/K8055.m \
-o ./K8055/K8055.o \
-arch ppc
echo "Building JNI shared library..."
gcc -c -I/System/Library/Frameworks/JavaVM.framework/Headers \
k8055usbio.m -o k8055usbio.so -arch ppc
echo "Compiling dynamic library with both..."
gcc -shared -fPIC -o ./lib/libk8055usbio.dylib k8055usbio.so \
./K8055/K8055.o -framework Foundation -framework IOKit -arch ppc
But when I try to System.load() it, I get the following error from the Java (1.5) program:
dyld: java bad CPU subtype in library: /libk8055usbio.dylib
Trace/BPT trap
I don't have any idea how to fix it, what CPU subtype should I be specifying?
You'll need to fiddle a couple of options. First, you'll want to explicitly specify an SDK using -isysroot, since newer SDKs will subvert you in various ways. Second, you'll want to pass -mmacosx-version-min=10.3 to indicate that you really want to run on 10.3. Using both of those options on a little test program, I get a binary that claims it ought to run on a G3. Here's my command line:
gcc-4.0 -arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk/ -mmacosx-version-min=10.3 -o testprog testarch.c
You can sanity check the CPU type/subtype in the header using otool -h, which for this example gives me:
$ otool -h testprogtestprog:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 18 0 0x00 2 11 1268 0x00000085
The zero there is CPU_SUBTYPE_POWERPC_ALL, per /Developer/SDKs/MacOSX10.4u.sdk/usr/include/mach/machine.h .

Categories