Write & call Swift code using Java’s JNI - java

As you see here one can perform native C/C++ method calls from Java code, thanks to JVM’s JNI. But how about performing calls of Swift methods? Is this possible or going to be possible (can be implemented in a reasonable time frame) as Swift becomes more popular?
I want to access Apple’s native API that is only accessible when one writes apps in either Objective-C or Swift. As the JVM is just being ported to ARMv8 (64-bit), I could also imagine the JVM as an alternative runtime for iOS apps in the future. But this might be the future... The present is: The JVM runs on Mac OS X and one can write apps for Mac OS X in Swift that can access some APIs that might be not accessible to Java apps in the same way.

Well, roughly 5½ years later, it turned out, it wasn't the future... No JVMs on iOS.
But you can definitely do it, i.e., call Swift APIs from Java. That said, it's quite cumbersome, because AFAIK, you have to take a detour via C/C++.
Here's the deal:
As you know, you can use JNI to call C code.
From C you can call Swift.
The following relies heavily on this question.
Code
Your Java code is in helloworld/SwiftHelloWorld.java:
package helloworld;
public class SwiftHelloWorld {
static {
System.loadLibrary("SwiftHelloWorld");
}
public static native void printHelloWorldImpl();
public static void main(final String[] args) {
printHelloWorldImpl();
}
}
Now write the native C code (file helloworld_SwiftHelloWorld.c):
#include <jni.h>
#include <stdio.h>
#include "helloworld_SwiftHelloWorld.h"
#include "helloworld_SwiftHelloWorld_swift.h"
JNIEXPORT void JNICALL Java_helloworld_SwiftHelloWorld_printHelloWorldImpl
(JNIEnv *env, jclass clazz) {
int result = swiftHelloWorld(42);
printf("%s%i%s", "Hello World from JNI! ", result, "\n");
}
Which uses a header file named helloworld_SwiftHelloWorld_swift.h for our (yet to be written) Swift code:
int swiftHelloWorld(int);
Finally, our Swift code resides in SwiftCode.swift:
import Foundation
// force the function to have a name callable by the c code
#_silgen_name("swiftHelloWorld")
public func swiftHelloWorld(number: Int) -> Int {
print("Hello world from Swift: \(number)")
return 69
}
Building
To build all this, we first have to compile the Swift code to a dynamic library:
swiftc SwiftCode.swift -emit-library -o libSwiftCode.dylib -Xlinker -install_name -Xlinker libSwiftCode.dylib
We use the -Xlinker directives to ensure that the dylib's location is relative.
Before we can create the C dylib, we first have to generate the Java headers:
javac -h . helloworld/SwiftHelloWorld.java
Now that we have the Java headers and the Swift dylib, we can compile the C dylib, which links against the Swift dylib:
gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin/" -o libSwiftHelloWorld.dylib -dynamiclib helloworld_SwiftHelloWorld.c libSwiftCode.dylib
Now that everything is in place, we must make sure that both dylibs are in the same directory and that that directory can be found by Java, i.e., you may need to set -Djava.library.path=<dir of your dylibs>.
Et voilà!
Swift called from Java!

Related

How to fix Java 15 JNI "UnsatisfiedLinkError: A dynamic link library (DLL) initialization routine failed"

I have found other posts of people having this exact error, but not one thus far has had a solution that worked for me. For reference, here are the things I have found:
https://community.oracle.com/tech/developers/discussion/2233828/jni-link-error-a-dynamic-link-library-dll-initialization-routine-failed
JNI UnsatisfiedLinkError: A dynamic link library (DLL) initialization routine failed
https://www.debugcn.com/en/article/5175409.html
https://coderanch.com/t/132356/engineering/java-lang-UnsatisfiedLinkError
Either their solution was not relevant to my particular scenario, or it did not fix the issue for me.
Everything is being compiled on the command line with a Windows 10 computer and using GCC (gcc-5.1.0-tdm64-1-c++) for compiling the C++ portions into a .dll, and JDK 15.0.1's javac tool. There are three relevant files here, one being the header file derived from the java file.
Main.java:
public class Main {
static {
System.load("C:\\Users\\17659\\Documents\\Programming\\C++ & Java - JNI Tests\\library.dll");
//System.loadLibrary("library");
}
public static void main(String[] args) {
new Main().outputText();
}
private native void outputText();
}
Main.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */
#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Main
* Method: outputText
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Main_outputText
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Library.cpp:
#include <iostream>
#include "Main.h"
JNIEXPORT void JNICALL Java_Main_outputText(JNIEnv * a, jobject b)
{
std::cout << "testing";
}
They are contained all within the folder with the absolute path of C:\Users\17659\Documents\Programming\C++ & Java - JNI Tests. With a command prompt set to that as the current directory, I run the following commands in order:
g++ -c -o Library.o -I"C:\Users\17659\Documents\jdk-15.0.1\include" -I"C:\Users\17659\Documents\jdk-15.0.1\include\win32" Library.cpp
g++ -shared -o library.dll Library.o
javac Main.java
java Main
Despite the multiple things I have tried, I always get this same error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\17659\Documents\Programming\C++ & Java - JNI Tests\library.dll: A dynamic link library (DLL) initialization routine failed
at java.base/jdk.internal.loader.NativeLibraries.load(Native Method)
at java.base/jdk.internal.loader.NativeLibraries$NativeLibraryImpl.open(NativeLibraries.java:383)
at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:227)
at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:169)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2407)
at java.base/java.lang.Runtime.load0(Runtime.java:747)
at java.base/java.lang.System.load(System.java:1857)
at Main.<clinit>(Main.java:3)
I have used nm on the resulting .dll to make sure the name of the function is correct, and it does seem to be exactly as it should.
The entire point of this little project of mine is to figure out how JNI works, since I have a plan to write a small portion of a program in C++. The rest of the program though would work best in Java (for me). I do not know what I need to do to get this program to work, I have spent approximately 2 hours of googling and fiddling attempting to get it to function. This is on a 64-bit OS. How can I make this program run and print out the very little amount of text I would like it to print out?
Update: As per #JornVernee removing the line #include <iostream> and replacing the std::cout with a printf() to write to the console did actually work. So my question now becomes this: why does including a standard C++ header cause an error?
Well, #JornVernee effectively nailed the issue right on the head. It was a mismatch between the standard library I had for C++ and the one being loaded. I changed the version of GCC I was using to a more up-to-date version, recompiled the entire project, and the program works now.

Porting a CPP application to Android

I need to port a CPP project to Android but I somehow got stuck because of the following things that I am not sure of:
Do I need to use some kind of java wrapper for my CPP project at all, i.e is it necessarily that I use Android SDK to integrate my application with Android? If there is another way, which one would that be?
I have seen some people claiming they have been able to manipulate their cmake file and some custom android-cmake toolchain to build their “.so” or eventually an “.apk” from their project. Would it be possible without a java wrapper to manipulate the cmake files of the cpp project to build your project? (source: Build Android NDK project with Cmake)
From my experience, I would go with using the android java entry point, otherwise you will most likely bump into problems (you can make full native android apps , but I strongly advise against it).
One of the reasons is that you will want SDK function calls from inside your CPP, and using reflection on the java environment from CPP isn't trivial.
The steps would be the following :
Create a very simple C code that will server as bridge to your CPP code . Here are some sample C functions that I've commonly used :
OnApplicationStart
OnApplicationPaused
OnApplicationResumed
OnApplicationUpdate
OnTouchReceived
Export these functions and load them in your Java code (lookup JNI on how to do this)
Handle all Android-specific actions in Java, and all application specific actions in cpp
So the answer to your 1st question is that a java wrapper isn't mandatory, but it's HIGHLY recommended.
To answer your 2nd question :
Yes, you can use cmkae, ant, cygwin , allot of command tools that will end up creating your apk (It's up to you on how you feel comfortable).You will still use the android compiler since you are targeting arm.
The difference is that you need to change in your manifest.xml the entry point of the application from a normal activity to a native activity ( http://developer.android.com/reference/android/app/NativeActivity.html ) .
As you can see, the difference isn't the build system, it's the way you define your entry point.
As a friendly advice, try using the minimal java wrapper approach. You might get to better results sooner, and it won't take you more then 1 week of research on the web on how to link java code to cpp.
EDIT :
As of demand, I will shortly explain how I would approach the process of porting a CPP application to Android :
Rethink your application to work as a shared library , using a C entry point :
a.Create a simple C application that will load yourCPPApp.dll (or .so if you are on linux)
b. In your .dll create the minimum necessary extern "C" functions to be exported in order for you to give the necessary information to your dll
For simplicity, we'll assume we have 3 methods :
void StartApplication();
bool OnApplicationUpdate();
void OnScreenTouched(int x, int y);
c. Implement the simple C project that will make the calls to these methods externaly (so the .exe will call the methods from the .dll ! )
Sample code :
#include "myCPPapp.h"
int main(int arg, char** argv)
{
StartApplication();
srand(time(NULL));
while (OnApplicationUpdate())
{
// we assume we have a 480x640 resolution
OnScreenTouched(rand()%480,rand()%640);
}
return 0;
}
Now that we have things working in full native with a .exe and a .dll , time to make it work with a .apk and a .so
a. Rename the exposed methods from myCppApp into java compatible prototypes
extern "C" {
JNIEXPORT void JNICALL Java_com_sample_nativebridge_OnApplicationStart(JNIEnv env, jobject thiz);
JNIEXPORT jboolean JNICALL Java_com_sample_nativebridge_OnApplcationUpdate(JNIEnv env, jobject thiz);
JNIEXPORT void JNICALL Java_com_sample_nativebridge_OnScreenTouched(JNIEnv env, jobject thiz, jint x, jint y);
}
b. create the java class nativebridge (case sensitive) in the package com.sample (you need t respect the names in order for correct linkage to native)
class nativebridge {
public static native void OnApplicationStart();
public static native boolean OnApplicationUpdate();
public static native void OnScreenTouched(int x, int y);
}
c. add the load library statement in the native bridge in order to have your library loaded at runtime
class nativebridge {
....
static {
System.loadLibrary("myCppApp");
// notice that the lib prefix and .so sufix aren't part of the name
}
}
d. compile your CPP code with the armeabi compiler and create libmyCPPApp.so (ndk build system , or whatever you'd like... i would go with the ndk, it's quite easy , just go into the folder with Android.mk and call $ANDROID_NDK_BUILD_PATH/build )
At this point you will need to createa a .mk file that will compile your myCppApp code, but this is out of scope, you will need to do this research on your own (it's quite trivial once you get the hang of it).
c. use the native methods from the bridge inside your java app wherever you see fit.
A very good tip would be to go through a hello world sample of ndk :
http://www.ntu.edu.sg/home/ehchua/programming/android/android_ndk.html
Enjoy.

Wrap a DLL into Java

I've got some code to talk to a hardware device on windows which is working in C++. The code does something pretty simple to react to a button push on the device and I have this compiled into a dll with an observer that is called when the button is pushed. I now need to interface this with a big Java program.
I was intending to use JNA but it only works with C and I cannot see how to do this with an Observer pattern in C. I've looked into using BridJ and SWIG (both of which cliam to work on C++ DLLs) to create an interface to the compiled dll (with the associated header file) but BridJ creates huge amounts of files (in JNAeratorStudio) and then stops with an error and I cannot see how to get started on Windows with SWIG (I'm using Visual Studio Express rather than full Visual Studio).
Does anyone know of a tutorial on integrating a C++ DLL with a Java Program - SWIG looks pretty promising but the tutorials are 'swampy'.
I've put some simple C code to talk to the DLL below:
#include <iostream>
#include <stdio.h>
#include "DeepFocusControlDll.h"
using namespace std;
using namespace DeepFocusControl;
class MyObserver : public DeepFocusControl::DeepFocusObserver{
void Event(){
printf("***Button Pushed***");
}
};
int main()
{
DeepFocusControl::AVA6Control* dfc = new DeepFocusControl::AVA6Control();
MyObserver* observer = new MyObserver();
dfc->AddObserver(observer);
bool connected = dfc->IsConnected();
printf("Connected %s\n", (connected)?"true":"false");
bool connectresult = dfc->Connect();
printf("Connecting %s\n", (connectresult)?"true":"false");
connected = dfc->IsConnected();
printf("Connected %s\n", (connected)?"true":"false");
dfc->SetHardwareAppLaunch(false);
char waitChar;
cin >> waitChar;
dfc->SetHardwareAppLaunch(true);
dfc->RemoveObserver(observer);
dfc->Disconnect();
printf("Disconnected\n");
cin >> waitChar;
}
If anyone knows a simpler way to use an observer pattern on this I can happily recode the C side too.
It sounds like you're looking for SWIG's directors feature. In its simplest form you can use directors with SWIG by giving an interface file like:
%module(directors=1) MyModule
%feature("director");
%{
#include "mydll.h"
%}
%include "mydll.h"
Given a header file "mydll.h":
class Observer {
public:
virtual void frobination() = 0;
virtual ~Observer() {}
};
inline void bar(Observer *o) {
o->frobination();
}
Then you can run SWIG:
swig -Wall -java -c++ mymodule.i
This will generate three Java classes: MyModule, MyModuleJNI and Observer. Of these MyModule will contain all the free functions from your header file, exposed as static member functions since Java has no such thing as free functions. You can safely ignore MyModuleJNI - it's glue generated by SWIG for connecting MyModule to the real C++ implementations. You'll need to compile mymodule_wrap.cxx for MyModuleJNI (and hence MyModule) to work correctly though and load the DLL using System.loadLibrary before you call any functions from them.
The Observer class directly corresponds to the Observer interface in mydll.h. You should derive from it in Java and override the frobinate function to give it your own implementation:
public class Test extends Observer {
#Override
public void frobination() {
System.out.println("go go gadget frobinator");
}
public static void main(String[] argv) {
System.loadLibrary("mymodule");
Test t = new Test();
MyModule.bar(t);
}
}
Which I can compile and run to do exactly what you'd hope.
If you want you can automate the call to System.loadLibrary by adding:
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("mymodule");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
to your SWIG interface file.
If your real header file is that simple it should be that simple to get the same results too. If it's more complicated you can instruct SWIG to special case some of its wrapping in various ways.

Constness error in SWIG-generated wrapper code for a Director

So, I'm trying to use swig to wrap a c++ library to make JNI calls to it. But, the _wrap.cxx file that swig is creating for me won't compile cleanly in g++. What am I doing wrong?
Here's a simple test case that will reproduce the error, along with a couple of other cases that don't error. My header file:
class MyClass {
};
class MyDirectored {
public:
virtual void Overridable (MyClass const clz);
virtual ~MyDirectored();
};
and here's my .i file:
%module("directors="1") swigtest
%{
#include "swig.h"
%}
%feature("director") MyDirectored
%include "swig.h"
I'm attempting to build via the following:
swig -c++ -package gen -java -outdir gen swig.i
g++ -c swig_wrap.cxx -o swig_wrap.o
And the g++ step yields the following error:
swig_wrap.cxx: In member function 'virtual void SwigDirector_MyDirectored::Overridable(MyClass)':
swig_wrap.cxx:436: error: invalid conversion from 'const MyClass*' to 'MyClass*'
Which appears to be a legitimate complaint - the resulting swig_wrap.cxx file looks like (lots of snippage)
void SwigDirector_MyDirectored::Overridable (MyClass const clz) {
//...
jlong jclz;
//...
*((MyClass **)&jclz) = &clz; //Error on this line
//...
}
I get the same error in both swig 2.0.4 and 1.3.40, Linux and Windows. Any suggestions? Any g++ trick I could use to ignore the constness error?
Random notes: I can't control the input header, so changing the function signature is a no-go. It doesn't appear to matter what type the input parameter is - class or struct. Making it a const reference instead of a const value parameter does "fix" the error by causing SWIG to explicitly cast away the constness (but again, I can't change the input header).
Thanks in advance!

Calling Haskell from Java with C in between

This probably sounds like a nightmare, but I'd really like to get this working. I am using this example for the most part: Calling C from Haskell and am trying to get this working on ubuntu.
I am running this in java:
package test;
public class JniTest {
public native int fib(int x);
}
this in c after creating the .h file with javah: (test_JniTest.c)
#include "test_JniTest.h"
#include "Safe_stub.h"
JNIEXPORT jint JNICALL Java_test_JniTest_fib(JNIEnv * e, jobject o, jint f)
{
return fibonacci_hs(f);
}
and then for reference in haskell (before stub): (Safe.hs)
module Safe where
import Foreign.C.Types
fibonacci :: Int -> Int
fibonacci n = fibs !! n
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral
foreign export ccall fibonacci_hs :: CInt -> CInt
and this is what i'm trying to compile it with:
ghc -c -O Safe.hs
followed by:
ghc -shared -o libTest.jnilib -optc-O test_JniTest.c
-I/usr/lib/jvm/java-6-sun-1.6.0.26/include -I/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux
and I am getting this error:
/usr/bin/ld: test_JniTest.o: relocation R_X86_64_PC32 against
undefined symbol `fibonacci_hs' can not be used when making a shared
object; recompile with -fPIC /usr/bin/ld: final link failed: Bad value
collect2: ld returned 1 exit status
I am not a c expert by any means and have no idea what to do about this. I tried compiling various ways with -fPIC, but I kept on getting the same error. Any idea what I might be doing wrong?
Thanks!
Although I've pretty much answered this question here: Communication between Java and Haskell, since this issue is more about the error itself, I will be adding the details for that here. The issue stems from Haskell not supporting shared libraries very well, while Java requires them.
Buildings plugins as Haskell shared libs gives us this insight and workaround:
In principle you can use -shared without -dynamic in the link step. That would mean to statically link the rts all the base libraries into your new shared library. This would make a very big, but standalone shared library. However that would require all the static libraries to have been built with -fPIC so that the code is suitable to include into a shared library and we don't do that at the moment.
If we use ldd again to look at the libfoo.so that we've made we will notice that it is missing a dependency on the rts library. This is problem that we've yet to sort out, so for the moment we can just add the dependency ourselves:
$ ghc --make -dynamic -shared -fPIC Foo.hs -o libfoo.so \
-lHSrts-ghc6.11 -optl-Wl,-rpath,/opt/ghc/lib/ghc-6.11/
This is a workaround because it requires us to know the version of the rts library at build time.
If your goal is to actually get something done (as opposed to just playing around with JNI) I suggest tackling this as a garden variety RPC problem and utilizing one of the many framework/protocols for it:
Protocol Buffers from Google
Thrift from Facebook
Avro (well this is mostly a wire protocol)
From what you are trying to do, Thrift might be your best bet since it describes a full client/server RPC stack but I'm pretty sure any of them would pretty much work over a simple socket.

Categories