I had created the dynamic library for java using swig and cmake for learning purposes. I can't call a function in java from the same libary that I created. The swig doc told me this is the result of forgeting to compile and link the swig wrapper file to my native libary, but I'm very sure that I did that with cmake build.
CMakeList.txt
cmake_minimum_required (VERSION 2.6)
FIND_PACKAGE(SWIG REQUIRED)
find_package(Java REQUIRED COMPONENTS Runtime Development)
find_package(JNI REQUIRED)
INCLUDE(${SWIG_USE_FILE})
set(JAVA ${java_include_path} )
INCLUDE_DIRECTORIES(${JAVA} ${JAVA}/win32)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
SET_SOURCE_FILES_PROPERTIES(hello.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(hello.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(hello java hello.i hello.cpp)
SWIG_LINK_LIBRARIES(hello ${Java_LIBRARIES} ${JNI_LIBRARIES} ${CMAKE_CURRENT_SOURCE_DIR})
hello.cpp
#include "hello.hpp"
int adding(const int x, const int y)
{
return y + x;
}
hello.hpp
int adding(const int x, const int y);
hello.i
%module hello
%{
#include "hello.hpp"
%}
int adding(const int x, const int y);
Can anyone tell me what I"m doing wrong when I'm creating the dynamic library? Thank you for the assistance.
The reason why I know this is due to this error message in eclipse
Exception in thread "main" java.lang.UnsatisfiedLinkError: hello.helloJNI.adding(II)I
at hello.helloJNI.adding(Native Method)
at hello.hello.adding(hello.java:14)
at hello.Main.main(Main.java:14)
Which is the same kind of error message that the docs talk about.
The missing symbol in your error message is part of the JNI wrapper, not part of your library itself.
Usually this means that you've not called System.loadLibrary() for the native part of the SWIG module, before making the first call into it. Your CMake file looks like you've correctly linked the implementation, so it's not the error case you referred to from the documentation.
As well as manually calling:
System.loadLibrary("hello"); // The name of your DLL here
from your main method I like to use the following in my SWIG interface files when I'm targeting Java:
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("hello"); // The name of your DLL here
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
This causes the native library to be loaded automatically before it is needed, which seems most natural to Java programmers.
Related
I have a test project that works good. I tried to use the native library from there (and the same methods) in my other project and I get this error :
W/dalvikvm(22240): No implementation found for native Lcom/example/myapp/Serial;.open:(Ljava/lang/String;IIZ)Ljava/io/FileDescriptor;
this is the JNI code in Serial class:
// JNI
private native static FileDescriptor open(String path, int baudrate,
int flags, boolean flowCon);
public native void close();
static {
System.loadLibrary("test_lib");
}
and I have "libtest_lib.so" in three folders in my libs folder : armeabi, armeabi-v7a, x86.
I debugged the app and it seems the 'System.loadLibrary' is ineed called before the call of native method 'open'. So I can't see other options for the error..
You probably copied and pasted from another project redefine your prototype in you c file as Java_Pacakage_JavaParentClass_functionName(JNIEnv* env, jobject thiz)
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!
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.
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.
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!