Loading methods of a specific class from a C++ library using JNI - c++

I have a C++ library xyz. It has many classes like xyzA, xyzB etc. I want to use the method getAge() from the class xyzA which is in the xyz library.
The xyz.so file already exists.
Steps I have followed:
Created a Java class xyz.java
class xyz {
public native int getAge();
public static void main(String[] args) {
new xyz().getAge();
}
static {
System.loadLibrary("xyz");
}
}
Created the header for the Java class.
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class xyz */
#ifndef _Included_xyz
#define _Included_xyz
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: xyz
* Method: getAge
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_xyz_getAge
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
The cpp wrapper class looks like:
#include <stdio.h>
#include "xyz.h"
#include <jni.h>
JNIEXPORT jint JNICALL Java_xyz_getAge(JNIEnv *, jobject)
{
// some code
}
I successfully compile the class as follows:
gcc -fPIC -shared -l stdc++ -I/grid/0/gs/java/jdk64/current/include -I/grid/0/gs/java/jdk64/current/include/linux xyz.cpp
Then run the Java prog as:
java -Djava.library.path=/grid/0/tmp/direct/lib xyz
I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: xyz.getAge()I
at xyz.getAge(Native Method)
at xyz.main(xyz.java:6)
It cannot find the method getAge() specific to the class xyzA. How can that method be accessed? Also, is the library getting linked through my wrapper class?
Any pointers would be appreciated.
Thanks.

If you are running on Unix, the shared library has to be named libxyz.so, not xyz.so.

This error normally means that the library has been successfully loaded,
but that there is an inconsistency in the signature of the function.
Globally, your code looks correct, but we do put an extern "C" in
front of JNIEXPORT in our code base. We don't use the generated
headers, so the definition of the function is the only place we could
specify extern "C". In your case, I think that the compiler is
supposed to recognize that the function declared in the header and the
one defined in your .cpp are the same, and define the function as
extern "C", but having never done it this way, I'm not 100% sure. You
can verify by doing something like:
nm -C libxyz.so | egrep getAge
The function should appear as a C function, with a T in the second
column; without the -C, it should appear unmangled. Note that the
slightest difference in the definition and the declaration will mean
that you're defining a different function; I don't see one in the code
you've posted, but it's worth double checking.
(I'd also wrap the call to LoadLibrary in a try block, just to be sure.)
EDITED to add some additional information:
I'm not sure when and how Linux links the additional libraries needed;
we've always loaded all of our libraries explicitly. You might try
adding a call to dlopen in either JNI_OnLoad or the constructor of a
static object. (I would recommend this anyway, in order to control the
arguments to dlopen. We found that when loading several different
.so, RTTI didn't work accross library boundaries if we didn't.) I
would expect not doing so to result in a loader error, but it all
depends on when Linux tries to load libxyz.so; if it only does so when
the JVM calls dlsym, then you'll get the above error. (I think this
depends on the arguments the JVM passes to dlopen when you call
java.lang.System.LoadLibrary: if it passes RTLD_LAZY or RTLD_NOW.
By forcing the load in JNI_OnLoad or the constructor of a static
object, you more or less guarantee that loader errors appear as loader
errors, and not link errors, later.)

Exported function names in C++ libraries are mangled: The plain function name is decorated with class and namespace names, parameter and return types. For instance, here is one of the methods from a boost library:
?estimate_max_state_count#?$perl_matcher#PB_WV?$alloca
tor#U?$sub_match#PB_W#boost###std##U?$regex_traits#_WV?$w32_regex_traits#_W#boos
t###boost###re_detail#boost##AAEXPAUrandom_access_iterator_tag#std###Z
The format of the name is not standardised and varies from compiler to compiler. The end result is that it is difficult to call an exported C++ member function unless you're writing another module in C++ and compiling it using the same compiler. Trying to call from Java is more trouble than it is worth.
Instead, if the C++ library is yours, export helper functions using the extern "C" calling convention:
Foo * foo;
extern "C"
{
void myfunc()
{
foo->bar(); // Call C++ function within a C-style function.
}
}
If the library is third-party, you should wrap it with your own library which exposes necessary functions using the C-style export, as per above.

Related

Calling a global function defined in C++ source file , from a C source file

Is there any way to call a C++ function from a C source file , without using extern "C" prior to the function declaration in the C++ file e.g :
//C++ source file
extern "C" void func_name();
void func_name()
{
....
}
The only way to not use extern "C" directly is to manually determine the mangled name and call that from C; which is essentially just doing extern "C" but manually. There's no point or purpose or alternative method with any merit whatsoever.
I'm not aware of any combination of C and C++ compilers that provide an officially supported way to do this. You're supposed to use extern "C" in the C++-side header files.
However, perhaps you have to anyway; I can think of several reasons other than homework, such as when you've got a third-party C++ library with an interface that could be invoked from C but the developers neglected to put extern "C" in the headers, and you can't recompile it.
There is usually an unofficial way to do it: you have to find out the mangled name of the C++ function, and any hidden parameters that it has (this is almost always treated as a hidden first parameter, and there may be others). You then write a declaration on the C side using the mangled name and the full parameter list.
Here is a very simple example that will work with GCC on most operating systems and CPUs:
/* file1.cpp */
#include <cstdio>
void foo()
{
puts("hello from foo");
}
/* file2.c */
#include <stdio.h>
extern void _Z3foov(void);
int main(void)
{
puts("hello from main");
_Z3foov();
return 0;
}
Because this is homework I am not going to give you a more complicated example, but I am going to point you at the so-called "Itanium C++ ABI", which specifies how the mangling and the hidden parameters work with GCC and Clang on most operating systems and CPUs. (Be aware that MSVC uses a completely different, undocumented, scheme. I have heard rumors that Clang can optionally use MSVC's scheme now but I'm not sure I believe it, considering how gargantuan a reverse-engineering job it would have been. ;-)
(In case you're wondering, mangled names are how function and operator overloading are implemented in the linker. If my file1.cpp had defined both void foo(void) and void foo(int), that would have produced an object file exporting the mangled names _Z3foov and _Z3fooi.)
You could write a separate translation unit, let's say mycppunit.cpp containing your void func_name() implementation without any extern "C" declarations. Compile this translation unit into a binary using a C++ compiler, yielding, for example, a mycppunit.o binary; then, use a command line tool like nm to find out how the function name has been mangled: For example:
nm mycppunit.o | grep func_name
would give something like
000000010006a920 T __Z9func_namev
Then you may assume that there will be a function void _Z9func_namev() available, and you can write in a translation unit, e.g. `my_c_program.c, the following:
void _Z9func_namev();
int main() {
_Z9func_namev();
}
Compiling this with a C compiler and linking it together with the mycppunit.o will give the desired result.
Hope it is what you are looking for.

JNI how to call a C/C++ function in C/C++?

Searching for JNI, I've always found something like:
Method in C/C++, call in Java
Method in Java, call in C/C++
But never method in C/C++, call in C/C++ using JNI.
I ask that, because I have a 3rd party Java library, which has some C/C++ libraries, and I've always used Java to call them. And I would like now, to create some program using C instead of Java. Unfortunately they don't provide the any API in C/C++, only in Java.
Is it possible, if yes how can I try to do it?
Thank you in advance!
The JNI methods are always publicly exposed with an extern C signature.
This means that you could just link to the JNI dll directly if you have the method signature. (which you can easily get if you look at the Java class native method signature).
But you will have to make sure you give the method the environment it expects.
This means pass the "this" object and environment object.
You'll have to make sure that the class loader object has the right packages loaded in it. In most cases JNI code assumes the environment that called the method has the right class loader in it already (because the java method was called...).
And there's also an issue with local references that JNI code might assume are released automatically from the stack (which doesn't happen in C++ native threads).
Anyway, it would look like this:
//MyClass.java
class MyClass
{
native void Blah();
}
//method signature, some header file:
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_MyClass_Blah
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
//Call the function, C++ code
Java_MyClass_Blah(myEnv, myClassInstanve);

When to use extern "C"?

I know how to use extern "C" but what are the conditions when you have to use it?
extern "C" tells the C++ compiler not to perform any name-mangling on
the code within the braces. This allows you to call C functions from
within C++.
For example:
#include <string.h>
int main()
{
char s[] = "Hello";
char d[6];
strcpy_s(d, s);
}
While this compiles fine on VC++. But sometimes this is written as:
extern "C" {
#include <string.h>
}
I don't see the point. Can you give a real example where extern "C" is necessary?
You use extern "C" to prevent name mangling inside header files and your C++ object files for libraries or objects that have already been compiled without mangling.
For example, say you have a widget library which was compiled with a C compiler so that its published interface is non-mangled.
If you include the header file as is into your code, it will assume the names are mangled and those mangled versions are what you'll tell the linker to look for.
However, since you'll be asking for something like function#intarray_float_charptr and the widget library will have only published function, you're going to run into problems.
However, if you include it with:
extern "C" {
#include "widget.h"
}
your compiler will know that it should try to use function, the non-mangled version.
That's why, in header files for C stuff meant to be included in C _or C++ programs, you'll see things like:
#ifdef __cplusplus
extern "C" {
#endif
// Everything here works for both C and C++ compilers.
#ifdef __cplusplus
}
#endif
If you use a C compiler to include this, the #ifdef lines will cause the extern "C" stuff to disappear. For a C++ compiler (where __cplusplus is defined), everything will be non-mangled.
One very common use of extern "C" when you are exporting a function from a library. If you don't disable C++ name mangling you can otherwise make it very hard for clients of your library to name your function. And likewise, when going in the other direction, when you are importing a function that has been exported with C linkage.
Here is a concrete example of where things break and need extern "C" to get fixed.
module.h:
int f(int arg);
module.c:
int f(int arg) {
return arg + 1;
}
main.cpp:
#include "module.h"
int main() {
f(42);
}
Since I am mixing C and C++, this won't link (of the two object files, only one will know f under its C++ mangled name).
Perhaps the cleanest way to fix this is by making the header file compatible with both C and C++:
module.h:
#ifdef __cplusplus
extern "C" {
#endif
int f(int arg);
#ifdef __cplusplus
}
#endif
When you link with libraries that are written in C extern tells the compiler not to decorate the names so that the linker can find the functions. In C++ function names et al have information for the linker e.g. argument types and sizes contained in the name.
If you are producing a binary library A that exposes a function that you would like to call from binary B.
Imagine A is A.dll and B is B.exe and you are on a Windows system.
C++ does not describe a binary layout such that B knows how to call A. Typically this problem is worked around by using the same compiler to produce A and B. If you want a more generic solution you use the extern keyword. This exposes the function in a C manner. C does describe a binary format so that different binaries from different compilers can talk to each other.
See:
http://en.wikipedia.org/wiki/Application_binary_interface
http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B
If, inside your C++ code, you #include a header for an external library (coded in C) and if the functions there are not declared extern "C" they wont work (you'll get undefined reference at link time).
But these days, people coding C libraries and providing header files for you tend to know that, and often put the extern "C" in their header file (suitably protected with #ifdef __cplusplus)
Perhaps a better way to understand is to use (assuming you have a Linux system) the nm utility to show you the (unmangled) names used in a library or an executable.

Calling methods of the main program from run time loaded Dll

I have a (big and complex) C++ program with its own classes and methods.(obviously)
I would like to load at runtime a dll. From the main program i want to call a function inside the dll passing a class instance , and this function will use the method of this class.
In pseudo code
Main program:
class MyClass{
myattr1();
myattr2();
mymethod1();
mymethod2();
}
void main(){
MyClass* object = &(new MyClass())
handle_of_the_dll = *some function that load the dll*
dllfunc = getfunc(handle_of_the_dll, "interesting_function")
dllfunc(object)
[...etc...]
and the dll
#ifdef __cplusplus
extern C {
#endif
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
#include all the needed headers from main program, where the class is defined
EXPORT void interesting_functionn(MyClass object){
object.mymethod1();
}
#ifdef __cplusplus
}
#endif
Is this valid/doable/right?
EDIT:
i know that this would be a poor design for a general program, but this method is intended to give the users the ability to use their custom dll that can access the api of the main program. Something like Cpython modules
It is valid and doable. Generate a sample DLL in visual C++ and the code will have all the bases covered. Replace the static linking in the client with LoadLibrary and GetProcAdress.
Name mangling could be an issue, DependencyWalker will help you there.
Keep a low profile with emory management. For example, if you use a memory manager on one side but not on the other, your begging for trouble.
I'd say it's possible, but with all due respect, it looks like bad design to me. There is a circular dependency between the main program and the dll: the program calls functions from the dll, and viceversa. In an ideal design, the main program would consume some dll functions, and the dll wouldn't know anything about the main program, or in general, about its clients.
Perhaps you should isolate the functions from the main program that the dll needs to use in a common dll or static lib which both the program and dll use.
As long as the methods are declared virtual and you pass the object by reference or pointer there should be no problems. If however you want to access non-virtual methods of the class you will need to put it's implementation in a separate DLL.

Specify ordinals of C++ exported functions in a DLL

I am writing a DLL with mixed C/C++ code. I want to specify the ordinals of the functions I'm exporting. So I created a .DEF file that looks like this
LIBRARY LEONMATH
EXPORTS
sca_alloc #1
vec_alloc #2
mat_alloc #3
sca_free #4
vec_free #5
mat_free #6
...
I would like to specify the ordinals of my C++ functions and class methods too. I have tried using the Dependency Walker to add the mangled names of my functions to the .DEF file:
??0CScalar##QAE#XZ #25
??0CScalar##QAE#O#Z #26
??0CScalar##QAE#ABV0##Z #27
??1CScalar##QAE#XZ #28
But this has failed. Any ideas why this could be happening?
EDIT: kauppi made a good observation, so I'm adding more information to the question.
Platform: Windows (and I'm not interested in portability)
Compiler: Microsoft's C++ compiler (I'm using VS2005)
Why I want to do this?: Using the ordinals has the advantage of letting me call exported C++ functions from C code.
Well, I don't have experience with ordinals (which look like some ugly, compiler-specific thing), but I can help you with making C++/C code compatible.
Suppose, in C++, that your header file looks like this:
class MyClass
{
void foo(int);
int bar(int);
double bar(double);
void baz(MyClass);
};
You can make it C-compatible by doing the following:
#ifdef __cplusplus
#define EXTERN_C extern "C"
// Class definition here; unchanged
#else
#define EXTERN_C
typedef struct MyClass MyClass;
#endif
EXTERN_C void MyClass_foo (MyClass*, int);
EXTERN_C int MyClass_bar_int (MyClass*, int);
EXTERN_C double MyClass_bar_double (MyClass*, double);
EXTERN_C void MyClass_baz (MyClass*, MyClass*);
In the C++ source file, you just define the various extern "C" functions to pass to the desired member functions, like this (this is only one; the rest work similarly)
extern "C" void MyClass_foo (MyClass* obj, int i)
{
obj->foo(i);
}
The code will then have a C interface, without having to change the C++ code at all (except for declarations in the header; but those could also be moved to another file "myclass_c.h" or the like). All the functions declared/defined extern "C" won't be mangled, so you can do other operations on them easily. You will also probably want functions to construct/destroy instances of MyClass (you can, of course, use new/delete for this).
You said "Using the ordinals has the advantage of letting me call exported C++ functions from C code." , I am sorry to say that this is incorrect.
C++ class member functions have special calling convention which requires an invisible this value passed in an implementation-specific register/parameter. And also you need a class instance to pass, which you can not accomplish in C.
The only 2 uses of this that I know, are faster dynamic linking of the DLL and smaller Import Table. Just inspect mfc70.dll in system32 directory with the dependancy walker.