- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
大家好!
我知道这里有太多关于 JNI 的主题,但是,我是 JNI 新手,所以我决定写一个新的。
我正在尝试编写一个 JNI 来访问 Java 层中的某些 C++ 类,但我收到错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: arm.test.lib.FooClass.init(I)V
at arm.test.lib.FooClass.init(Native Method)
at arm.test.lib.FooClass.<init>(FooClass.java:13)
at arm.test.app.Main.main(Main.java:9)
<end of output>
我有以下项目树
来源
├── build
├── CMakeLists.txt
├── 富
| ├── 来源
| | ├── foo.cpp
| | └── foo.h
| ├──包括
| | └── foo.h -> ../src/foo.h
| └── CMakeLists.txt
└── java-jni
├── c
├── CMakeLists.txt
│ └── jni_wrapper.cpp
└── java
└── 来源
└── ARM
└── 测试
├── 应用程序
│ └── Main.java
└── 库
└── FooClass.java
源文件夹中的 CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(java-cpp)
include_directories(foo)
option(BUILD_TESTS "Build the test suite (requires foo)" ON)
if(BUILD_TESTS)
enable_testing()
endif()
add_subdirectory(foo)
add_subdirectory(java-jni)
foo 文件夹中的 CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(foo)
add_compile_options(-std=c++11)
set(PROJECT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set(SRCS_PATH "${PROJECT_PATH}/src")
set(CPPLIB_INCLUDE_DIR "${PROJECT_PATH}/include" CACHE INTERNAL "foo include directories")
include_directories(${CPPLIB_INCLUDE_DIR})
file(GLOB SRCS "${SRCS_PATH}/*.cpp" "${SRCS_PATH}/*.h")
add_library(${PROJECT_NAME} SHARED ${SRCS})
Foo 是一个简单的类、构造函数和一些函数...
#ifndef CLASS_H
#define CLASS_H
class Foo {
private:
int m_nb;
public:
Foo(int &n_nb);
int getValue() const;
void increment();
};
#include <iostream>
#include "foo.h"
Foo::Foo(int &n_nb) :m_nb(n_nb)
{
std::cout << n_nb << std::endl;
}
int Foo::getValue() const
{
return this->m_nb;
}
void Foo::increment()
{
this->m_nb++;
}
以及来自 java-jni 的 CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# REQUIRED JAVA
FIND_PACKAGE(Java COMPONENTS Development)
INCLUDE(UseJava)
SET(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8")
SET(JAVA_SOURCE_FILES
arm/test/app/Main.java
arm/test/lib/FooClass.java)
# Build Java classes
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/java/bin")
SET(class_files)
FOREACH(_java_file ${JAVA_SOURCE_FILES})
# _java_file: relative file name
# _class_file: relative class name
STRING(REGEX REPLACE "\\.java$"
".class" _class_file
"${_java_file}")
ADD_CUSTOM_COMMAND(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/java/bin/${_class_file}"
COMMAND
${Java_JAVAC_EXECUTABLE}
${CMAKE_JAVA_COMPILE_FLAGS}
-sourcepath "${CMAKE_CURRENT_SOURCE_DIR}/java/src"
-d "${CMAKE_CURRENT_BINARY_DIR}/java/bin"
"${CMAKE_CURRENT_SOURCE_DIR}/java/src/${_java_file}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/java/src/${_java_file}")
LIST(APPEND class_files "java/bin/${_class_file}")
ENDFOREACH()
ADD_CUSTOM_TARGET(JavaJNIClasses ALL DEPENDS ${class_files})
# Make the JNI header file
ADD_CUSTOM_COMMAND(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/FooClass_jni.h"
COMMAND
${Java_JAVAH_EXECUTABLE}
-o "${CMAKE_CURRENT_BINARY_DIR}/include/FooClass_jni.h"
-classpath "${CMAKE_CURRENT_BINARY_DIR}/java/bin"
arm.test.lib.FooClass
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/java/bin/arm/test/lib/FooClass.class")
ADD_CUSTOM_TARGET(JavaJNIHeaders ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/FooClass_jni.h")
# Require JNI
FIND_PACKAGE(JNI REQUIRED)
# Builds the JNI wrapper
INCLUDE_DIRECTORIES("${CPPLIB_INCLUDE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}/include"
${JNI_INCLUDE_DIRS}
)
ADD_LIBRARY(foo_jni SHARED c/jni_wrapper.cpp)
link_directories("${CMAKE_BINARY_DIR}/foo")
SET_TARGET_PROPERTIES(
foo_jni PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}"
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}")
TARGET_LINK_LIBRARIES(foo_jni foo)
ADD_DEPENDENCIES(foo_jni JavaJNIHeaders)
# Testing
IF(BUILD_TESTS)
FIND_PACKAGE(Java COMPONENTS Runtime)
ADD_TEST(
NAME run-jni
COMMAND
"${Java_JAVA_EXECUTABLE}"
-cp java-jni/java/bin
-Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}
arm.test.app.Main
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
ENDIF()
C 路径内部是 C 到 java 的包装器。
#include "foo.h"
#include "FooClass_jni.h"
static jfieldID _get_self_id(JNIEnv *env, jobject thisObj)
{
static int init = 0;
static jfieldID fidSelfPtr;
if(!init)
{
jclass thisClass = env->GetObjectClass(thisObj);
fidSelfPtr = env->GetFieldID(thisClass, "self_ptr", "J");
}
return fidSelfPtr;
}
static Foo *_get_self(JNIEnv *env, jobject thisObj)
{
jlong selfPtr = env->GetLongField(thisObj, _get_self_id(env, thisObj));
return *(Foo**)&selfPtr;
}
static void _set_self(JNIEnv *env, jobject thisObj, Foo *self)
{
jlong selfPtr = *(jlong*)&self;
env->SetLongField(thisObj, _get_self_id(env, thisObj), selfPtr);
}
extern "C" JNIEXPORT void JNICALL Java_arm_test_lib_Foo_init(JNIEnv *env, jobject thisObj, jint nb)
{
Foo *self = new Foo(nb);
_set_self(env, thisObj, self);
}
extern "C" JNIEXPORT jint JNICALL Java_arm_test_lib_Foo_getValue(JNIEnv *env, jobject thisObj)
{
Foo *self = _get_self(env, thisObj);
return self->getValue();
}
extern "C" JNIEXPORT void JNICALL Java_arm_test_lib_Foo_increment(JNIEnv *env, jobject thisObj)
{
Foo *self = _get_self(env, thisObj);
self->increment();
}
extern "C" JNIEXPORT void JNICALL Java_arm_test_lib_Foo_finalize(JNIEnv *env, jobject thisObj)
{
Foo *self = _get_self(env, thisObj);
if(self != NULL)
{
delete self;
_set_self(env, thisObj, NULL);
}
}
当我在 java-jni 中运行 cmake 文件时,javah 会生成我的这个文件。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class arm_test_lib_FooClass */
#ifndef _Included_arm_test_lib_FooClass
#define _Included_arm_test_lib_FooClass
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: arm_test_lib_FooClass
* Method: init
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_arm_test_lib_FooClass_init
(JNIEnv *, jobject, jint);
/*
* Class: arm_test_lib_FooClass
* Method: getValue
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_arm_test_lib_FooClass_getValue
(JNIEnv *, jobject);
/*
* Class: arm_test_lib_FooClass
* Method: increment
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_arm_test_lib_FooClass_increment
(JNIEnv *, jobject);
/*
* Class: arm_test_lib_FooClass
* Method: finalize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_arm_test_lib_FooClass_finalize
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
最后我得到了 FooClass.java
package arm.test.lib;
public class FooClass{
static {
System.loadLibrary("foo_jni");
}
private long self_ptr;
public FooClass(int nb)
{
init(nb);
}
private native void init(int nb);
public native int getValue();
public native void increment();
protected native void finalize();
}
代码可用于:
https://github.com/eduardoaugustojulio/java-cpp-study
最好的问候。
最佳答案
您的 jni_wrapper.cpp 是为 Java 类 Foo 编写的,但您尝试从类 FooClass 中使用它。
关于c++ - C++ 类 UnsatisfieldLinkError 的 JNI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46960634/
大家好! 我知道这里有太多关于 JNI 的主题,但是,我是 JNI 新手,所以我决定写一个新的。 我正在尝试编写一个 JNI 来访问 Java 层中的某些 C++ 类,但我收到错误: Exceptio
我是一名优秀的程序员,十分优秀!