【问题标题】:JNI JVM Invocation ClasspathJNI JVM 调用类路径
【发布时间】:2014-07-21 16:00:51
【问题描述】:

我正在使用 Cygwin 编写一个启动 Java 虚拟机的小型 C 程序(我使用的库需要 POSIX 环境)。到目前为止,只要我将所有类与可执行文件放在同一个文件夹中,我就能够让它工作。但是,我想指定一个包含我要运行的应用程序的实际 JAR 文件。这似乎不起作用,FindClass 只是返回一个空值。就像我说的那样,我已将其缩小到类路径设置的问题,因为我可以将我的 jar 文件提取到与可执行文件相同的目录中,它会起作用。这是我的代码的一个子集:

我一直在大致遵循本指南:http://www.inonit.com/cygwin/jni/invocationApi/

int main( int argc, char *argv[] )
{
        void* jvmDllHandle;
        JNIEnv* jenv;
        JavaVM* jvm;
        JavaVMInitArgs args;
        JavaVMOption options[1];
        jclass cls;
        jmethodID mainMethod;
        jobjectArray appArgs;
        jstring arg0;

        assert( cygwin_internal( CW_SYNC_WINENV ) != 1UL );

        jvmDllHandle = LoadLibrary( "c:\\Path\\To\\Application\\jre\\bin\\server\\jvm.dll" );
        createJavaVM = dlsym( jvmDllHandle, "JNI_CreateJavaVM" );

        args.version = JNI_VERSION_1_6;
        args.nOptions = 1;
        options[0].optionString = "-Djava.class.path=c:\\Path\\To\\Application\\TheJarFile.jar";
        args.options = options;
        args.ignoreUnrecognized = JNI_FALSE;

        createJavaVM( &jvm, (void **) &jenv, &args );

        cls = (*jenv)->FindClass( jenv, "some/package/MainClass" );
        assert( cls != NULL );  // This fails.

        /// Omitted...

        return 0;
}

尝试使用 -classpath 和 -cp

int main( int argc, char *argv[] )
{
        void* jvmDllHandle;
        JNIEnv* jenv;
        JavaVM* jvm;
        JavaVMInitArgs args;
        JavaVMOption options[1];
        jclass cls;
        jmethodID mainMethod;
        jobjectArray appArgs;
        jstring arg0;

        assert( cygwin_internal( CW_SYNC_WINENV ) != 1UL );

        jvmDllHandle = LoadLibrary( "c:\\Path\\To\\Application\\jre\\bin\\server\\jvm.dll" );
        createJavaVM = dlsym( jvmDllHandle, "JNI_CreateJavaVM" );

        args.version = JNI_VERSION_1_6;
        args.nOptions = 1;
        options[0].optionString = "-classpath c:\\Path\\To\\Application\\TheJarFile.jar";
        args.options = options;
        args.ignoreUnrecognized = JNI_FALSE;

        createJavaVM( &jvm, (void **) &jenv, &args );

        cls = (*jenv)->FindClass( jenv, "some/package/MainClass" );
        assert( cls != NULL );  // This fails.

        /// Omitted...

        return 0;
}

我如何错误地指定类路径?

【问题讨论】:

  • 您是否真的在寻找 java 类路径选项?
  • 什么意思?我尝试使用 -classpath 和 -cp 如果这就是你所说的。
  • 是的,这就是我要说的。你能显示那个代码吗?
  • 我无法调用 java -classpath 或 java -cp。我需要在启动 JVM 之前配置 Cygwin 环境,这样我就可以使用一些需要 POSIX 层的 JNI 库。所以我需要创建自己的启动器。
  • this post 中的一个 cmets 提到有时 Windows 文件分隔符 ('\') 会出现问题。使用 Unix 样式分隔符 ('/') 再次尝试第一个示例

标签: java c java-native-interface cygwin


【解决方案1】:

在 x86-64 上,Oracle Windows JDK 标头将 jint 定义为 long。这是 32 位,使用 Microsoft 编译器(编写 Oracle JDK),但使用 Cygwin gcc 是 64 位。由于JavaVMInitArgs 包含一些这种类型的字段,因此它的二进制布局会因这种差异而改变。

我通过提供本地 jni.h 标头来解决此问题:

#include "stdint.h"

#define __int64 int64_t
#define long int32_t
#include "jni_md.h"
#undef long

#include_next "jni.h"

我在 long 重新定义的范围内只包括 jni_md.h,因为它不包括任何其他标头,而 jni.h 包括几个我们不希望受到影响的标准标头.

为确保它始终包含在 Oracle 标头之前,请使用 -I 编译器选项将其目录添加到 #include 路径。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多