GraalVM: How To Call C-Function From Java ...with an Annotation 📎
#include <stdio.h>
extern "C" int multiply(int a,int b){
printf("c function called with %d and %d",a,b);
return a * b;
}
...from Java on GraalVM, you have to declare a static, native method annotated with @CFunction
:
import java.io.IOException;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.function.CFunction.Transition;
import org.graalvm.nativeimage.c.function.CLibrary;
@CLibrary("calculator")
public class Calculator {
@CFunction(transition = Transition.NO_TRANSITION)
public static native int multiply(int a,int b);
public static void main(String[] args) throws IOException {
System.out.println("calling c with parameter");
var result = multiply(2,21);
System.out.println("-----------------> result: " + result);
}
}
you will have to download and install GraalVM first.
To compile the code above, you have to "run" on GraalVM. The command java -version
should contain "GraalVM":
openjdk version "17.0.4" 2022-07-19
OpenJDK Runtime Environment GraalVM CE 22.3.0-dev (build 17.0.4+7-jvmci-22.3-b02)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.0-dev (build 17.0.4+7-jvmci-22.3-b02, mixed mode, sharing)
Also the following GraalVM components have to be installed (gu list
output):
ComponentId Component name
----------------------------------------------
graalvm GraalVM Core
llvm LLVM Runtime Core
llvm-toolchain LLVM.org toolchain
native-image Native Image
Install any missing components with gu install [ComponentId]
e.g gu install llvm
To create the native image:
- Compile the c code:
$LLVM_TOOLCHAIN/clang -shared -o libcalculator.so calculator.cc
- Compile the Java code:
javac -cp . -d . *.java
- Create native image:
native-image -cp target --verbose -H:CLibraryPath=[FULLY QUALIFIED PATH TO: libcalculator.so] Calculator NativeCalculator
Now you can call the calculator with: NativeCalculator
.
Output:
calling c with parameter
-----------------> result: 42
c function called with 2 and 21
attention
- In case
$JAVA_HOME/bin/lli --print-toolchain-path
throws an exception, consider using the latest dev build. - The value of the annotation
@CLibrary("calculator")
contains the name of the *.so file without the "lib" prefix: libcalculator.so -> calculator.so - The flag:
-H:CLibraryPath=
has to point to the fully qualifed path of the directory containing thelibcalculator.so
The entire code and build script is available from: graalvm-hello-java-c