Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake JNI error

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.

like image 967
STiGMa Avatar asked Sep 25 '13 00:09

STiGMa


1 Answers

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.

like image 154
sakra Avatar answered Oct 01 '22 23:10

sakra