I've written a binding C++ class that calls java from C++. I am trying to compile the binding class using CMake (because the tool that will use the binding class uses CMake).
However I receive the following error:
CMakeFiles/JNIWrapper.dir/JNIWrapper.cpp.o: In function `createVM(JavaVM_**)':
JNIWrapper.cpp:(.text+0x52): undefined reference to `JNI_CreateJavaVM'
collect2: ld returned 1 exit status
make[2]: *** [JNIWrapper] Error 1
make[1]: *** [CMakeFiles/JNIWrapper.dir/all] Error 2
make: *** [all] Error 2
Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.6)
project(AProject)
FIND_PACKAGE(JNI REQUIRED)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/lib/jvm/java-6-openjdk-amd64/include -I/usr/lib/jvm/java-6-openjdk-amd64/include/linux -L/usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server")
SET(CMAKE_EXE_LINKER_FLAGS "-ljvm")
# add the binary tree directory to the search path for include files
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${JNI_INCLUDE_DIRS})
# add the executable
add_executable (JNIWrapper JNIWrapper.cpp)
Any suggestion is appreciated.
PS: I have tried to compile it using the traditional way and by writing a makefile. I followed that example and wrote the CMakeLists.txt script above.
The following CMakeLists.txt
sketches the steps required to build a sample JNI project with CMake:
cmake_minimum_required (VERSION 3.0)
find_package(Java REQUIRED)
find_package(JNI REQUIRED)
include(UseJava)
enable_testing()
project (JNIFoo)
# compile JNIFoo.java to class file
set(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.6" "-target" "1.6")
add_jar(JNIFoo JNIFoo.java)
get_target_property(_jarFile JNIFoo JAR_FILE)
get_target_property(_classDir JNIFoo CLASSDIR)
# generate JNIFoo.h stub
set (_stubDir "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_command(
OUTPUT JNIFoo.h
COMMAND ${Java_JAVAH_EXECUTABLE} -verbose
-classpath ${_classDir}
-d ${_stubDir}
-jni JNIFoo
DEPENDS JNIFoo
)
# generate libfoo.jnilib
include_directories(${JNI_INCLUDE_DIRS} ${_classDir} ${_stubDir})
add_library(foo MODULE foo.c JNIFoo.h)
set_target_properties(foo PROPERTIES SUFFIX ".jnilib")
target_link_libraries(foo ${JNI_LIBRARIES})
# add test to run JNIFoo
add_test(NAME TestJNIFoo
COMMAND ${Java_JAVA_EXECUTABLE}
-Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}
-cp ${_jarFile} JNIFoo)
The file JNIFoo.java
contains a Java class that declares a function in foo.c
as a native method nativeFoo
. foo.c
contains the C implementation of the method nativeFoo
.
The CMake function add_jar compiles the Java class to a jar file and, as a side effect, creates a class file which needs to be passed as an input to the javah
C stub file generator executable. A custom command is used to invoke javah
to generate the stub header JNIFoo.h
as an output file.
Because Java uses System.loadLibrary
to load JNI libraries at runtime, the JNI library must be generated as a MODULE
library using the CMake command add_library. Adding JNIFoo.h
as a source file ensures that JNIFoo.h
will be created before the library is compiled. The compiled JNI library needs to be linked with the JDK JNI libraries contained in the variable JNI_LIBRARIES
. JNI_INCLUDE_DIRS
contains the the JNI include dirs to use.
Finally, a test is added to run the class JNIFoo with the JVM. The system property java.library.path
must be set to the directory containing the generated JNI library libfoo.jnilib
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With