3

I try to call this minimal C code (file TEST.c):   void Java_TEST_run() {}
from this Java code (file Example.java):

public class Example {
    public static void main(String args[]) {
        System.out.println("START");
        TEST test = new TEST();
        test.dll_call();
        System.out.println("ALL DONE!");
    }
}

class TEST {
    public void dll_call() {
        run();
    }

    static {
        try {
            System.out.println("Load DLL = start ");
            System.load("/home/user/Desktop/TEST.dll");
            System.out.println("Load DLL = finish ");
        } catch (UnsatisfiedLinkError e) {
            System.err.println("Native code library failed to load.\n");
            System.exit(1);
        }
    }
    public native void run();
}

I create a library in the following way:

gcc -c TEST.c                     
g++ -shared -o TEST.dll TEST.o

If I compile with GCC (and create lib even with G++!) everything works fine, but if I compile with G++ (g++ -c TEST.c), I receive the following output with error, when running the Java example:

START
Load DLL = start 
Load DLL = finish 
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'void TEST.run()'
    at TEST.run(Native Method)
    at TEST.dll_call(Example.java:21)
    at Example.main(Example.java:9)
Jorengarenar
  • 2,705
  • 5
  • 23
  • 60
newbee7
  • 63
  • 4

2 Answers2

3

C and C++ are different languages and follows different compilation rules. If you compile with g++, then the code will be treated as C++ not C. It's common pitfall of misconception that C++ is superset of C.

C++ does something called name mangling: encoding function and variable names into unique names so that linkers can separate common names in the language. Thanks to it, features like function overloading are possible.

Let's consider an example (source):

int  f (void) { return 1; }
int  f (int)  { return 0; }
void g (void) { int i = f(), j = f(0); }

The above may be changed by compiler to:

int  __f_v () { return 1; }
int  __f_i (int)  { return 0; } 
void __g_v () { int i = __f_v(), j = __f_i(0); }

Even though the name of g() is unique, is still mangled. Name mangling applies to all C++ symbols.

If you want to prevent name mangling you need to use extern "C"{} block (but the above example will result in error as C doesn't have function overloading).

Jorengarenar
  • 2,705
  • 5
  • 23
  • 60
  • Thank you, I agree that it seems to be related to the name mangling. I tried some combinations, incl. "__run_v" but it did not work out for me... Anyway, the extern"C" command did the trick. – newbee7 Jun 09 '21 at 09:23
1

As explained in the other answer, the reason why this fails is name mangling by the C++ compiler.

To solve this (i.e. to make C++ work with Java JNI), you need to decorate your C++ functions with an extern "C" language linkage declaration:

extern "C"
void Java_TEST_run() {}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214