How to use SWIG to wrap std::function objects? - java

I have seen quite a few similar questions, but have not found a solution to my particular problem. I am attempting to SWIGify some C++11 code that uses std::function, so I can use it in my Java application.
I have encountered shared pointers like this:
virtual std::shared_ptr<some::ns::TheThing> getTheThing(unsigned short thingID);
and successfully handled them with the shared_ptr directive like so:
%shared_ptr(some::ns::TheThing);
I have encountered vectors of shared pointers like this:
virtual std::vector<std::shared_ptr<some::ns::TheThing>> getAllTheThings() const = 0;
and successfully handled them with a template like so:
%template(ThingVector) std::vector<std::shared_ptr<some::ns::TheThing>>;
Now I have a method like this:
void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);
and I cannot get SWIG to wrap it properly. I have tried using %callback, directors, %template, and %inline functional code, as I have seen examples with all of these things, but have not been able to get anything that seems close to working. Here is a little more context around the function call if that helps (sanitized and reduced):
thing_callback.h
#include <functional>
namespace some {
namespace ns {
/**
* Hold some callbacks.
*/
class ThingCallbacks {
public:
/**
* Registers a callback
* #param func The callback function
*/
void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);
};
}
}
Update
Based on Flexo's great answer below, I am much closer to a solution. I was able to get the examples below working exactly as advertised. I tried incorporating it into my actual code, but ran into issues. To expand on my earlier simplified example, here is my definition of TheThing:
test_thing.h
#ifndef THE_THING_H
#define THE_THING_H
#include <string>
namespace some {
namespace ns {
class TheThing {
public:
virtual ~TheThing() {};
virtual unsigned long longThing() const = 0;
virtual std::string stringThing() const = 0;
};
}
}
#endif /* THE_THING_H */
And here is my .i file. To have as few moving parts as possible, I've basically just taken the int and double from the code provided in the answer below, and replaced them with a shared pointer to my object.
func_thing_test.i
%module(directors="1") Thing
%include "stl.i"
%include "std_function.i"
%include "std_shared_ptr.i"
%shared_ptr(some::ns::TheThing);
%typemap(javadirectorin) std::shared_ptr<some::ns::TheThing> "new $typemap(jstype, some::ns::TheThing)($1,false)";
%typemap(directorin,descriptor="Lsome.ns.typemap(jstype, some::ns::TheThing);") std::shared_ptr<some::ns::TheThing> %{
*($&1_type*)&j$1 = &$1;
%}
%include "test_thing.h"
%include "thing_callback.h"
%{
#include <memory>
#include "test_thing.h"
#include "thing_callback.h"
%}
%std_function(Functor, void, std::shared_ptr<some::ns::TheThing>);
%{
#include <iostream>
void add_and_print(std::shared_ptr<some::ns::TheThing> thing) {
std::cout << "here\n";
}
%}
%callback("%s_cb");
void add_and_print(std::shared_ptr<some::ns::TheThing>);
%nocallback;
%inline %{
std::function<void(std::shared_ptr<some::ns::TheThing>)> make_functor() {
return [](std::shared_ptr<some::ns::TheThing>){
std::cout << "make functor\n";
};
}
void do_things(std::function<void(std::shared_ptr<some::ns::TheThing>)> in) {
std::cout << "inside do things\n";
}
%}
test_thing.h is what I just posted above, and thing_callback.h is the code I posted in my original question. This all compiles through the swig, c++, and Java chain without error, but it looks like swig is having a little trouble connecting the dots between the c++ and Java. It creates these three classes:
SWIGTYPE_p_f_std__function__f_std__shared_ptr__some__ns__TheThing____void____void
SWIGTYPE_p_f_std__shared_ptr__some__ns__TheThing____void
SWIGTYPE_p_std__functionT_void_fstd__shared_ptrT_some__ns__TheThing_tF_t
And unfortunately, most of the methods from the simple Java main code now take or return these objects, which make them fairly unusable. Any idea how to fix this? Thank you!
A little more detail for completeness: I am using the following three scripts to compile and run the code. The parameters are slightly different, but I don't think it matters. On my end it is set up as an Eclipse maven project. These scripts reside in the root of my project, headers and swig files reside in src/main/resources, java source files reside in src/main/java, and java compiled classes reside in target/classes. Eclipse performs the java compilation.
swigthing.sh
MODULE_NAME=Thing
PACKAGE=some.ns
OUTDIR=./src/main/java/some/ns
I_FILE=./src/main/resources/func_thing_test.i
mvn clean
rm $OUTDIR/*.*
mkdir -p $OUTDIR
swig -java -c++ -module $MODULE_NAME -package $PACKAGE -outdir $OUTDIR $I_FILE
./compileThingSwigTest.sh
compileThingSwigTest.sh
#!/bin/bash
pushd src/main/resources
g++ -c -std=gnu++11 -fpic \
func_thing_test_wrap.cxx \
-I/usr/lib/jvm/java/include \
-I/usr/lib/jvm/java/include/linux
g++ -shared func_thing_test_wrap.o -o libFunc.so
popd
runThingTest.sh
pushd target/classes
java -Xmx512M -Xms512M -Djava.library.path=. some.ns.test.RunThingTest
popd
Last Update
Fixed the code above to pass the right parameters to std_function. Now between the question and answer there is a complete working example of what I was after.

Although SWIG doesn't provide a std_function.i natively we can build one ourselves this with a bit of work. My answer here is a more generalised version of my a previous of mine answer, looking at this problem for a specific instance and targeting Python. I'll go through several iterations of it, which define a %std_function macro for generic std::function wrapping.
I'm assuming there are four things you want to achieve from a wrapping of std::function, which become our main requirements:
We want to be able to call std::function objects from within Java code.
The wrapped std::function objects need to get passed around like any other object, including crossing the language boundaries in either direction.
It should be possible to write std::function objects inside of Java, which can be passed back to C++ without having to modify existing C++ code that works on std::function objects (i.e. maintaining type erasure of std::function cross language)
We should be able to construct std::function objects in Java using C++ pointer to function types.
I'm going to work through these and show how we can achieve this. Where possible I'll keep the solution language agnostic too.
For the purposes of discussion I'm glossing over the shared_ptr part of your question, it doesn't actually change things because as you've got shared_ptr working that's actually sufficient to use it in this scenario too, it would just make my examples more verbose needlessly.
The solution I'm working towards is actually modelled after the existing shared_ptr support in SWIG. I've put together a test interface to illustrate how it will be used:
%module test
%include "std_function.i"
%std_function(Functor, void, int, double);
%{
#include <iostream>
%}
%inline %{
std::function<void(int,double)> make_functor() {
return [](int x, double y){
std::cout << x << ", " << y << "\n";
};
}
%}
Basically to use this all you need do is include the file "std_function.i" and then use the macro %std_function which takes arguments as:
%std_function(Name, Ret, ...)
You call this once per instantiation of the std::function template you want to wrap, where Name is what you want to call the type in Java, Ret is the return type and then the remaining (variadic) arguments are the inputs to your function. So in my test interface above I'm basically looking to wrap std::function<void(int,double)>.
Writing a first version of "std_function.i" isn't actually too tricky. All you need to get basic working requirements #1 and #2 is:
%{
#include <functional>
%}
%define %std_function(Name, Ret, ...)
%rename(Name) std::function<Ret(__VA_ARGS__)>;
%rename(call) std::function<Ret(__VA_ARGS__)>::operator();
namespace std {
struct function<Ret(__VA_ARGS__)> {
// Copy constructor
function<Ret(__VA_ARGS__)>(const std::function<Ret(__VA_ARGS__)>&);
// Call operator
Ret operator()(__VA_ARGS__) const;
};
}
%enddef
This includes the C++ header file in the generated wrapper code once and then sets up the macro for usage in interfaces. SWIG's support for C++11 variadic templates isn't actually very helpful for us in this usage scenario, so the macro I wrote basically re-implements the default template expansion functionality using C99 variadic macro arguments (which are much better supported). Coincidentally this means the SWIG code we're writing will work with 2.x or even some 1.3.x releases. (I tested with 2.x). Even if/when your version of SWIG does have %template support that works with std::function retaining this macro is still useful for the rest of the glue that makes it actually callable.
The manual expansion of the std:function template is limited to just the bits we care about for our usage: the actual operator() and a copy constructor that might come in handy.
The only other thing to be done is renaming operator() to something that matches the target language, e.g. for Java renaming it to be just a regular function called "call", or if you were targeting Python to __call__ or using tp_slots if required.
This is now sufficient to let our interface work, to demonstrate it I wrote a little bit of Java:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
test.make_functor().call(1,2.5);
}
}
Which I compiled with:
swig2.0 -Wall -c++ -java test.i
g++ -Wall -Wextra -std=c++11 test_wrap.cxx -o libtest.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -shared -fPIC
javac run.java
LD_LIBRARY_PATH=. java run
and it worked.
Requirement #4 is pretty easy to cross off the list now at this point. All we need to do is tell SWIG there's another constructor in std::function which accepts compatible function pointers:
// Conversion constructor from function pointer
function<Ret(__VA_ARGS__)>(Ret(*const)(__VA_ARGS__));
And then we can use this with the %callback mechanism in SWIG, our test interface file becomes:
%module test
%include "std_function.i"
%std_function(Functor, void, int, double);
%{
#include <iostream>
void add_and_print(int a, double b) {
std::cout << a+b << "\n";
}
%}
%callback("%s_cb");
void add_and_print(int a, double b);
%nocallback;
%inline %{
std::function<void(int,double)> make_functor() {
return [](int x, double y){
std::cout << x << ", " << y << "\n";
};
}
%}
and the Java we use to call this is then:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
test.make_functor().call(1,2.5);
new Functor(test.add_and_print_cb).call(3,4.5);
}
}
Which we compile and run identically successfully at this point.
(Note that it's normal and desirable to see some Java classes created at this point that start with the name "SWIGTYPE_p_f_..." - these wrap the "pointer to function" types that are used by the pointer to function constructor and callback constants)
Requirement #3 is where things start to get trickier. Essentially we've hit the same problem as I answered on making SWIG generate an interface in Java previously, except now we're looking to do it within a macro more generically.
It turns out that in this instance because the interface we want to generate is fairly simple we can use some tricks inside our macro to make SWIG generate it for us.
The main thing that we need to do in order to make this work is to setup SWIG directors to provide cross-language polymorphism and allow something written in Java to implement a C++ interface. This is the class generated with the suffix "Impl" in my code.
To make things "feel right" to Java developers we want to still use the same type for both C++ and Java implemented std::function objects. Even if std::function::operator() were virtual we still don't want to have SWIG directors use that type directly as it's pretty common to pass std::function by value which would lead to type slicing problems. So when a Java developer extends our std::function objects and overrides call we need to do some extra work to make it so that C++ which uses that object actually calls the Java implementation given that we can't just use directors to handle this automatically.
So what we do looks a little bit weird. If you construct a Java object that is meant to implement std::function then there's a special, protected constructor for that. This constructor leaves the swigCPtr member variable, which normally points to a real C++ object as 0 and instead creates an anonymous wrapper object that implements the "Impl" interface and simply proxies everything back to the call member of the Java object.
We have another typemap too that gets applied, in Java, everywhere we pass a std::function object to C++. Its role is to detect which case we have - a C++ implemented std::function object, or a Java one. In the C++ case it does nothing special and everything proceeds as normal. In the Java case it takes the proxy object and asks C++ to convert it back to another, separate std::function instance which gets substituted instead.
This is enough to get us the behaviour we want in both languages without anything that feels weird on either side (other than a lot of mechanical lifting that happens transparently).
The catch here is that it's non-trivial to automatically construct the proxy object. Java has dynamic proxy classes as part of the reflection API, but these only implement interfaces, not extend abstract classes. One possibility I did try to use was void call(Object ...args) on the Java side, which is a variadic function argument. Whilst legal this didn't seem to actually override any cases in the super class as would be needed.
What I ended up doing was adapting some macros to iterate over variadic macro arguments in the way I wanted. This is a fairly sensible solution given that we already decided to use variadic C99 macro arguments for other reasons. This mechanism gets used four times in total in my solution, once in the function declaration and once in the delgated call for both Java and C++. (C++ has perfect forwarding properties retained and Java needs a typemap lookup to be performed, so they are distinct in each and every case).
There's also a custom typemap to simplify some of the Java code - in a void function it's not legal to write return other_void_function();, so we would need to special case void functions if it weren't for that.
So let's see what that looks like in reality. First up is the run.java I used for testing, it's only slightly modified from previous examples to add a Java implementation of the std::function object.
public class run extends Functor {
public static void main(String[] argv) {
System.loadLibrary("test");
test.make_functor().call(1,2.5);
new Functor(test.add_and_print_cb).call(3,4.5);
Functor f = new run();
test.do_things(f);
}
#Override
public void call(int a, double b) {
System.out.println("Java: " + a + ", " + b);
}
}
The std_function.i is now substantially larger with all the changes outlined above:
%{
#include <functional>
#include <iostream>
#ifndef SWIG_DIRECTORS
#error "Directors must be enabled in your SWIG module for std_function.i to work correctly"
#endif
%}
// These are the things we actually use
#define param(num,type) $typemap(jstype,type) arg ## num
#define unpack(num,type) arg##num
#define lvalref(num,type) type&& arg##num
#define forward(num,type) std::forward<type>(arg##num)
// This is the mechanics
#define FE_0(...)
#define FE_1(action,a1) action(0,a1)
#define FE_2(action,a1,a2) action(0,a1), action(1,a2)
#define FE_3(action,a1,a2,a3) action(0,a1), action(1,a2), action(2,a3)
#define FE_4(action,a1,a2,a3,a4) action(0,a1), action(1,a2), action(2,a3), action(3,a4)
#define FE_5(action,a1,a2,a3,a4,a5) action(0,a1), action(1,a2), action(2,a3), action(3,a4), action(4,a5)
#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
%define FOR_EACH(action,...)
GET_MACRO(__VA_ARGS__, FE_5, FE_4, FE_3, FE_2, FE_1, FE_0)(action,__VA_ARGS__)
%enddef
%define %std_function(Name, Ret, ...)
%feature("director") Name##Impl;
%typemap(javaclassmodifiers) Name##Impl "abstract class";
%{
struct Name##Impl {
virtual ~Name##Impl() {}
virtual Ret call(__VA_ARGS__) = 0;
};
%}
%javamethodmodifiers Name##Impl::call "abstract protected";
%typemap(javaout) Ret Name##Impl::call ";" // Suppress the body of the abstract method
struct Name##Impl {
virtual ~Name##Impl();
protected:
virtual Ret call(__VA_ARGS__) = 0;
};
%typemap(maybereturn) SWIGTYPE "return ";
%typemap(maybereturn) void "";
%typemap(javain) std::function<Ret(__VA_ARGS__)> "$javaclassname.getCPtr($javaclassname.makeNative($javainput))"
%typemap(javacode) std::function<Ret(__VA_ARGS__)> %{
protected Name() {
wrapper = new Name##Impl(){
public $typemap(jstype, Ret) call(FOR_EACH(param, __VA_ARGS__)) {
$typemap(maybereturn, Ret)Name.this.call(FOR_EACH(unpack, __VA_ARGS__));
}
};
proxy = new $javaclassname(wrapper);
}
static $javaclassname makeNative($javaclassname in) {
if (null == in.wrapper) return in;
return in.proxy;
}
// Bot of these are retained to prevent garbage collection from happenign to early
private Name##Impl wrapper;
private $javaclassname proxy;
%}
%rename(Name) std::function<Ret(__VA_ARGS__)>;
%rename(call) std::function<Ret(__VA_ARGS__)>::operator();
namespace std {
struct function<Ret(__VA_ARGS__)> {
// Copy constructor
function<Ret(__VA_ARGS__)>(const std::function<Ret(__VA_ARGS__)>&);
// Call operator
Ret operator()(__VA_ARGS__) const;
// Conversion constructor from function pointer
function<Ret(__VA_ARGS__)>(Ret(*const)(__VA_ARGS__));
%extend {
function<Ret(__VA_ARGS__)>(Name##Impl *in) {
return new std::function<Ret(__VA_ARGS__)>([=](FOR_EACH(lvalref,__VA_ARGS__)){
return in->call(FOR_EACH(forward,__VA_ARGS__));
});
}
}
};
}
%enddef
And test.i is slightly expanded to validate the Java -> C++ passing of std::function objects and enable directors:
%module(directors="1") test
%include "std_function.i"
%std_function(Functor, void, int, double);
%{
#include <iostream>
void add_and_print(int a, double b) {
std::cout << a+b << "\n";
}
%}
%callback("%s_cb");
void add_and_print(int a, double b);
%nocallback;
%inline %{
std::function<void(int,double)> make_functor() {
return [](int x, double y){
std::cout << x << ", " << y << "\n";
};
}
void do_things(std::function<void(int,double)> in) {
in(-1,666.6);
}
%}
This compiled and ran as with the previous examples. It's worth noting that we've crossed into writing a lot of Java specific code - although the design would work for other languages if you were targeting Python it's a lot simpler to fix some of these issues using Python specific features.
There are two things I'd like to improve:
Use C++14 variadic lambdas to avoid the macro preprocessor magic I've used to keep them compatible with C++11. If you have C++ 14 the %extend constructor becomes:
%extend {
function<Ret(__VA_ARGS__)>(Name##Impl *in) {
return new std::function<Ret(__VA_ARGS__)>([=](auto&& ...param){
return in->call(std::forward<decltype(param)>(param)...);
});
}
}
When it comes to using this macro with std::shared_ptr as expected the macro itself needs no changes. There is however a problem with the implementation of the javadirectorin and directorin typemaps that get applied, which do prevent things from "just working". This is true even with a build of SWIG from "trunk". (There's an outstanding question on combining directors and shared_ptr)
We can work around that though, by adding two additional typemaps in the main .i file of our module right after the call to %shared_ptr:
%shared_ptr(some::ns::TheThing);
%typemap(javadirectorin) std::shared_ptr<some::ns::TheThing> "new $typemap(jstype, some::ns::TheThing)($1,false)";
%typemap(directorin,descriptor="L$typemap(jstype, some::ns::TheThing);") std::shared_ptr<some::ns::TheThing> %{
*($&1_type*)&j$1 = &$1;
%}
The first of these two typemaps is actually dead code because we forced the "call" method to be abstract in our abstract class, but it's easier to fix the compilation of this method than it is to suppress it. The second typemap is important. It's substantially similar to the normal "out" typemap in that it creates a jlong which is really just a representation of a C++ pointer, i.e. it prepares an object to go from C++, to Java.
Note that you might need to modify the descriptor attribute of the directorin typemap if you use packages in your module, either to "L$packagepath/$typemap(...);" or simply write it by hand.
This should remove the spurious "SWIGTYPE_p_sstd__shared_ptr..." type generated now as well. If you have virtual functions that return shared_ptr objects you'll need to write directorout and javadirectorout typemaps for them too. These can be base on the normal "in" typemap.
This was sufficient for my own simple testing with a modified Functor to work, at least with my version of SWIG checked out from the trunk today. (My test with 2.0.x failed and I didn't put much effort into making it work since this is a known work in progress area).

Related

Write a JNI wrapper around a C++ method

I have three C++ files that I want to use in Android studio.
Header.h
A.cpp (which contains the main method + other methods)
B.cpp
I have compiled them into a static library. Now I want to write the JNI wrapper around a C++ method and call it into the java part. Here is my wrapper so far :
#include <jni.h>
#include <string.h>
#include <stdlib.h>
extern "C" {
JNIEXPORT int JNICALL Java_cgi_pi_detect(? ,?) {
IplImage * byteQueryImage = loadByteImage ( ? );
if ( !byteQueryImage )
{
printf ( "couldn't load query image\n" );
return -1;
}
// Detect text in the image
IplImage * output = textDetection ( byteQueryImage, atoi(1));
cvReleaseImage ( &byteQueryImage );
cvSaveImage ( ? , output );
cvReleaseImage ( &output );
return 0;
}
}
I want to give it two pictures as arguments : the one to load IplImage * byteQueryImage = loadByteImage ( ? ); and the one to save cvSaveImage ( ? , output );.
What should be the jni types JNIEXPORT int JNICALL Java_cgi_pi_detect(? ,?) for these two arguments (if I consider that the pictures are .png) ?
Calling main() like that is fraught with peril. Which main() is going to be called? The JVM executable also has a main(). (And yes, I'm ignoring the "undefined behavior" as the question is about how to make it work.)
The hard way to get the main() you want is to compile it into a shared object, load that shared object, and find main() in that shared object yourself with runtime dynamic linking using dlopen() and dlsym() (error checking omitted):
#include <dlfcn.h>
...
// use a typedef for the function pointer
typedef int ( *main_func_t )( int, char ** );
...
// Handle to your .so with your "main()" in it
// make them static so they're only loaded once
static void *libHandle = NULL;
static main_func_t libMain = NULL;
if ( NULL == libHandle )
{
libHandle = dlopen( "yourLibName.so", RTLD_NOW );
libMain = ( main_func_t ) dlsym( libHandle, "main" );
}
...
// now call the main() in that library
int mainRetVal = libMain( argc, argv );
...
So that means you need two shared objects: the first "normal" one that holds your JNI calls, and the second that holds your "main()" that you want to call. The first "normal" JNI library will need to be linked with a dependency on libdl.so using an -ldl linker argument.
The easy way?
Rename the main() you want to call to something else and put it into your normal JNI shared object. Then just call it - it's no longer called main() so there's no longer any name conflict.
Even with all that, I suspect you still might run into problems - name collisions or incompatible libraries come to mind immediately.
An even easier way that will work?
Run it in a subprocess since that's the way it was designed to run, and it's effectively a black box anyway: you call it with arguments, it does whatever it does, and you get an int return value back. That's the same for a function call or a subprocess.
You can put the wrapper function in any file that will be compiled, new or existing. Unlike Java, in C++ the file name has no meaning for compiler.
You don't need to wrap other methods if you don't intend to call them independently from Java.
PS: note that the name Java_cgi_pi_detect of the wrapper function is derived from the Java class that defines this detect native method. Use javah tool to generate the correct name of the C function that implements a native Java method.

Java/C++ SWIG - Calling function with array parameter

So I have code that looks like this:
bool doSomething( unsigned int x, const myStruct1 typeOne[2], myStruct2 typeTwo[2] );
using swig I get java code:
public static boolean doSomething(long x, myStruct1 typeOne, myStruct2 type2){}
what I want is:
public static boolean doSomething(long x, myStruct1[] typeOne, myStruct2[] type2){}
I get that the problem is that SWIG can't know that my array in Java is only going to be 2 elements, as java declarations are sizeless.
I've tried using carrays.i in the swig interface. I used the arrays_fuctions instruction but it didn't change the method signature.
My next idea is going to code an inline function, in the SWIG file, that takes two parameters for each struct and then acts as a proxy down to the real function.
Any better ideas?
You can do this with the existing "arrays_java.i" SWIG library file.
There's a macro inside that file called JAVA_ARRAYSOFCLASSES that can be used as:
%module test
%include <arrays_java.i>
JAVA_ARRAYSOFCLASSES(myStruct1);
JAVA_ARRAYSOFCLASSES(myStruct2);
struct myStruct1 {};
struct myStruct2 {};
bool doSomething(unsigned int x, const myStruct1 typeOne[2], myStruct2 typeTwo[2]);
Which generates the following Java function:
public static boolean doSomething(long x, myStruct1[] typeOne, myStruct2[] typeTwo)
Which is exactly what you're after! (Take a look under the hood if you're curious - it's all standard usage of typemaps).

Does JNI and Java naming Convention matter when passing strings

Situation: I have a library of JNI files, the library is comprised of several functions that are called by the main header file in that JNI library (i.e., code1.h). I have a Java file (i.e., code2.java) that I want to pass to and from JNI header file (code1.h). I created a source code for the (code1.h) called (code1.c).
My question is: Does (code1.h), (code1.c), and (code2.java) have to be the same name for the communication between the JNI and the java?
EDIT: So (code1.h), (code1.c), and (code1.java) all have to be the same name in order for the (code1.java) to pass strings to/from (code1.c)/(code1.h)? And it is not possible to have (code2.java) pass strings to/from (code1.c)/(code1.h) because they are not named the same, is this correct?
For instance,
public class code1 { /*this is code2.java, but should the name be changed to (code1.java) to match that of the JNI?*/
static {
System.loadLibrary("myjni");
}
to pass strings to code1.h/code1.c
This will be compiled for android using Linux Debian"Wheezy" and Eclipse with Android SDK and NDK
While Java requires a match between compilation unit name (SomeClass.java being the name and public class SomeClass{ being the declaration, C does not require this.
You may name the C source and header files as you see fit as long as the function names/exported symbol names match the name of the native method on the java side. For example:
//JavaClass.java
public class JavaClass{
public native String getAString(String in);
}
And header would be:
// any name
JNIEXPORT jstring JNICALL
Java_JavaClass_getAString(JNIEnv *, jobject, jstring);
with matching C files. You could name this header catsMakeTheWorldGoRound.h for all Java cares.
Here is an example of what your "JNI object" should look like.
//In my experience, it is better to put the JNI object into a separate package.
package org.example;
public class Code1
{
static
{
// On a Linux system, the actual name of the library
// is prefixed with "lib" and suffixed with ".so"
// -- e.g. "myjni-java.so"
// Windows looks for "myjni-java.dll"
//
// On a Windows system, we also need to load the prequisite
// libraries first. (Linux loaders do this automatically).
//
String osname = System.getProperty("os.name");
if (osname.indexOf("win") > -1 || osname.indexOf("Win") > -1)
{
System.loadLibrary("myjni");
}
System.loadLibrary("myjni-java");
}
// Now we declare the C functions which we will use in our Java code.
public static native void foo(int bar);
public static native int bar(String foo);
//...
}
Given that you have compiled your JNI library correctly, you can then call the C functions from other Java classes like this:
//Again, in my experience, it is better to explicitly give the package name here.
org.example.Code1 Code1= new org.example.Code1();
Code1.foo(123);
int a= Code1.bar("Hello C function from Java function!");
Does this help you with your question? (I am not an expert in JNI, so I might not be able to help further.)

How to use the same C++ code for Android and iOS?

Android with NDK has support to C/C++ code and iOS with Objective-C++ has support too, so how can I write applications with native C/C++ code shared between Android and iOS?
Update.
This answer is quite popular even four years after I write it, in this four years a lot of things has changed, so I decided to update my answer to fit better our current reality. The answer idea does not change; the implementation has changed a little. My English also has changed, it has improved a lot, so the answer is more understandable to everyone now.
Please take a look at the repo so you can download and run the code I'll show below.
The Answer
Before I show the code, please take a lot on the following diagram.
Each OS has its UI and peculiarities, so we intend to write specific code to each platform in this regard. In other hands, all logic code, business rules, and things that can be shared we intend to write using C++, so we can compile the same code to each platform.
In the diagram, you can see the C++ layer at the lowest level. All shared code is in this segment. The highest level is regular Obj-C / Java / Kotlin code, no news here, the hard part is the middle layer.
The middle layer to iOS side is simple; you only need to configure your project to build using a variant of Obj-c know as Objective-C++ and it is all, you have access to C++ code.
The thing became harder on the Android side, both languages, Java and Kotlin, on Android, run under a Java Virtual Machine. So the only way to access C++ code is using JNI, please take time to read the basics of JNI. Fortunately, today's Android Studio IDE has vast improvements on JNI side, and a lot of problems are shown to you while you edit your code.
The code by steps
Our sample is a simple app that you send a text to CPP, and it converts that text to something else and returns it. The idea is, iOS will send "Obj-C" and Android will send "Java" from their respective languages, and the CPP code will create a text as a follow "cpp says hello to << text received >>".
Shared CPP code
First of all, we are going to create the shared CPP code, doing it we have a simple header file with the method declaration that receives the desired text:
#include <iostream>
const char *concatenateMyStringWithCppString(const char *myString);
And the CPP implementation:
#include <string.h>
#include "Core.h"
const char *CPP_BASE_STRING = "cpp says hello to %s";
const char *concatenateMyStringWithCppString(const char *myString) {
char *concatenatedString = new char[strlen(CPP_BASE_STRING) + strlen(myString)];
sprintf(concatenatedString, CPP_BASE_STRING, myString);
return concatenatedString;
}
Unix
An interesting bonus is, we can also use the same code for Linux and Mac as well as other Unix systems. This possibility is especially useful because we can test our shared code faster, so we are going to create a Main.cpp as follow to execute it from our machine and see if the shared code is working.
#include <iostream>
#include <string>
#include "../CPP/Core.h"
int main() {
std::string textFromCppCore = concatenateMyStringWithCppString("Unix");
std::cout << textFromCppCore << '\n';
return 0;
}
To build the code, you need to execute:
$ g++ Main.cpp Core.cpp -o main
$ ./main
cpp says hello to Unix
iOS
It is time to implement on the mobile side. As far as iOS has a simple integration we are starting with it. Our iOS app is a typical Obj-c app with only one difference; the files are .mm and not .m. i.e. It is an Obj-C++ app, not an Obj-C app.
To a better organization, we create the CoreWrapper.mm as follow:
#import "CoreWrapper.h"
#implementation CoreWrapper
+ (NSString*) concatenateMyStringWithCppString:(NSString*)myString {
const char *utfString = [myString UTF8String];
const char *textFromCppCore = concatenateMyStringWithCppString(utfString);
NSString *objcString = [NSString stringWithUTF8String:textFromCppCore];
return objcString;
}
#end
This class has the responsibility to convert CPP types and calls to Obj-C types and calls. It is not mandatory once you can call CPP code on any file you want on Obj-C, but it helps to keep the organisation, and outside your wrapper files you maintain a complete Obj-C styled code, only the wrappers file become CPP styled.
Once your wrapper is connected to the CPP code, you can use it as a standard Obj-C code, e.g. ViewController"
#import "ViewController.h"
#import "CoreWrapper.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *label;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString* textFromCppCore = [CoreWrapper concatenateMyStringWithCppString:#"Obj-C++"];
[_label setText:textFromCppCore];
}
#end
Take a look of how the app looks:
Android
Now it is time for Android integration. Android uses Gradle as the build system, and to C/C++ code it uses CMake. So the first thing we need to do is to configure the CMake on gradle file:
android {
...
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
...
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++14"
}
}
...
}
And the second step is to add the CMakeLists.txt file:
cmake_minimum_required(VERSION 3.4.1)
include_directories (
../../CPP/
)
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
../../CPP/Core.h
../../CPP/Core.cpp
)
find_library(
log-lib
log
)
target_link_libraries(
native-lib
${log-lib}
)
The CMake file is where you need to add the CPP files and header folders you will use on the project, on our example, we are adding the CPP folder and the Core.h/.cpp files. To know more about C/C++ configuration please read it.
Now the core code is part of our app it is time to create the bridge, to make the things more simple and organized we create a specific class named CoreWrapper to be our wrapper between JVM and CPP:
public class CoreWrapper {
public native String concatenateMyStringWithCppString(String myString);
static {
System.loadLibrary("native-lib");
}
}
Note this class has a native method and loads a native library named native-lib. This library is the one we create, in the end, the CPP code will become a shared object .so File embed in our APK, and the loadLibrary will load it. Finally, when you call the native method, the JVM will delegate the call to the loaded library.
Now the most strange part of Android integration is the JNI; We need a cpp file as follow, in our case "native-lib.cpp":
extern "C" {
JNIEXPORT jstring JNICALL Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString(JNIEnv *env, jobject /* this */, jstring myString) {
const char *utfString = env->GetStringUTFChars(myString, 0);
const char *textFromCppCore = concatenateMyStringWithCppString(utfString);
jstring javaString = env->NewStringUTF(textFromCppCore);
return javaString;
}
}
The first thing you will notice is the extern "C" this part is necessary to JNI work correctly with our CPP code and method linkages. You will also see some symbols JNI uses to works with JVM as JNIEXPORT and JNICALL. To you understand the meaning of those things, it is necessary to take a time and read it, for this tutorial purposes just consider these things as boilerplate.
One significant thing and usually the root of a lot of problems is the name of the method; it needs to follow the pattern "Java_package_class_method". Currently, Android studio has excellent support for it so it can generate this boilerplate automatically and show to you when it is correct or not named. On our example our method is named "Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString" it is because "ademar.androidioscppexample" is our package, so we replace the "." by "_", CoreWrapper is the class where we are linking the native method and "concatenateMyStringWithCppString" is the method name itself.
As we have the method correctly declared it is time to analyze the arguments, the first parameter is a pointer of JNIEnv it is the way we have access to JNI stuff, it is crucial to we make our conversions as you will see soon. The second is a jobject it is the instance of the object you had used to call this method. You can think it as the java "this", on our example we do not need to use it, but we still need to declare it. After this jobject, we are going to receive the arguments of the method. Because our method has only one argument - a String "myString", we have only a "jstring" with the same name. Also notice that our return type is also a jstring. It is because our Java method returns a String, for more information about Java/JNI types please read it.
The final step is to convert the JNI types to the types we use on CPP side. On our example, we are transforming the jstring to a const char * sending it converted to the CPP, getting the result and converting back to jstring. As all other steps on JNI, it is not hard; it is only boilerplated, all the work is done by the JNIEnv* argument we receive when we call the GetStringUTFChars and NewStringUTF. After it our code is ready to run on Android devices, lets take a look.
Approach described in the excellent answer above can be completely automated by Scapix Language Bridge which generates wrapper code on the fly directly from C++ headers. Here is an example:
Define your class in C++:
#include <scapix/bridge/object.h>
class contact : public scapix::bridge::object<contact>
{
public:
std::string name();
void send_message(const std::string& msg, std::shared_ptr<contact> from);
void add_tags(const std::vector<std::string>& tags);
void add_friends(std::vector<std::shared_ptr<contact>> friends);
};
And call it from Swift:
class ViewController: UIViewController {
func send(friend: Contact) {
let c = Contact()
contact.sendMessage("Hello", friend)
contact.addTags(["a","b","c"])
contact.addFriends([friend])
}
}
And from Java:
class View {
private contact = new Contact;
public void send(Contact friend) {
contact.sendMessage("Hello", friend);
contact.addTags({"a","b","c"});
contact.addFriends({friend});
}
}

How to change command prompt (console) window title from command line Java app?

How to change and update the title of the command prompt window from the java command line application? Every time I run my application, the command prompt window title shows:
C:\WINDOWS\system32\cmd.exe - java MyApp.
I'd like to change and update the window title as the java program runs, for example as wget(win32) updates downloading status in the title: Wget [12%].
Although I haven't tried it myself, in Windows, one can use the Win32 API call to SetConsoleTitle in order to change the title of the console.
However, since this is a call to a native library, it will require the use of something like Java Native Interface (JNI) in order to make the call, and this will only work on Windows 2000 and later.
Edit - A solution using JNI
The following is an example of using JNI in order to change the title of the console window from Java in Windows. To implement this, the prerequiste is some knowledge in C and using the compiler/linker.
First, here's result:
(source: coobird.net)
Disclaimer: This is my first Java application using JNI, so it's probably not going to be a good example of how to use it -- I don't perform any error-checking at all, and I may be missing some details.
The Java program was the following:
class ChangeTitle {
private static native void setTitle(String s);
static {
System.loadLibrary("ChangeTitle");
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 5; i++) {
String title = "Hello! " + i;
System.out.println("Setting title to: " + title);
setTitle(title);
Thread.sleep(1000);
}
}
}
Basically, the title is changed every 5 seconds by calling the setTitle native method in an external native library called ChangeTitle.
Once the above code is compiled to make a ChangeTitle.class file, the javah command is used to create a C header that is used when creating the C library.
Writing the native library
Writing the library will involve writing the C source code against the C header file generated by javah.
The ChangeTitle.h header was the following:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ChangeTitle */
#ifndef _Included_ChangeTitle
#define _Included_ChangeTitle
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: ChangeTitle
* Method: setTitle
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_ChangeTitle_setTitle
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
Now, the implementation, ChangeTitle.c:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <jni.h>
#include "ChangeTitle.h"
JNIEXPORT void JNICALL
Java_ChangeTitle_setTitle(JNIEnv* env, jclass c, jstring s) {
const jbyte *str;
str = (*env)->GetStringUTFChars(env, s, NULL);
SetConsoleTitle(str);
(*env)->ReleaseStringUTFChars(env, s, str);
};
A String that is passed into the native function is changed into an UTF-8 encoded C string, which is sent to the SetConsoleTitle function, which, as the function name suggests, changes the title of the console.
(Note: There may be some issues with just passing in the string into the SetConsoleTitle function, but according to the documentation, it does accept Unicode as well. I'm not too sure how well the code above will work when sending in various strings.)
The above is basically a combination of sample code obtained from Section 3.2: Accessing Strings of The Java Native Interface Programmer's Guide and Specification, and the SetConsoleTitle Function page from MSDN.
For a more involved sample code with error-checking, please see the Section 3.2: Accessing Strings and SetConsoleTitle Function pages.
Building the DLL
The part that turned out to take the most amount of time for me to figure out was getting the C files to compile into an DLL that actually could be read without causing an UnsatisfiedLinkError.
After a lot of searching and trying things out, I was able to get the C source to compile to a DLL that could be called from Java. Since I am using MinGW, I found a page form mingw.org which described exactly how to build a DLL for JNI.
Sources:
The Java Native Interface Programmer's Guide and Specification
Chapter 2: Getting Started - Details the process using JNI.
JNI-MinGW-DLL - Building a JNI DLL on MinGW with gcc.
This depends on your terminal emulator, but essentially it's just printing out control sequences to the console.
Now I'm not clear on what control sequences CMD.EXE responds to (I haven't one available to try this on) but I hear there's a command called TITLE which sets the title of the window. I tried piping TITLE's output to a file, but apparently, it doesn't actually set the title by outputting control characters. The START command can take a parameter which is title of the window followed by the command to run in the window. So something like
cmd TITLE "lovely Application that is in a command window." && "java" MyApp
REM or
start "lovely Application that is java based." java MyApp
Personally I would just bundle the whole thing with a shortcut where you can edit the properties such as the current directory, the command, it's parameters, and the window size, style and title (if I remember rightly). Give it a nice icon and people will use it.
Here's my solution using JNA:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class SetTitle {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "kernel32" : "c"),
CLibrary.class);
boolean SetConsoleTitleA(String title);
}
public static void main(String[] args) {
CLibrary.INSTANCE.SetConsoleTitleA("Testing 123");
System.exit(0);
}
}
You can use the CLITools Java library
following dlamblin's revelation ;-)
here's a python code.
note that there are 2 different commands in most programming languages:
system
exec
system will issue a system command, exec indeed spawns a new process. thus:
C:\>python
>>> import os
>>> os.system("title berry tsakala")
which works inside a running program. Just find the java equivalent.

Categories

Resources