无法使用 Cygwin 从 Java 运行 C 程序

Cannot run C program from Java using Cygwin

我正在尝试使用 JNI 制作我的第一个 Java/C 程序。这是 'my' 代码的样子 - 它是从 this 网站复制的:

/* HelloWorld.java */

public class HelloWorld {
    native void helloFromC();
    static {
        System.loadLibrary("ctest");
    }
    static public void main(String argv[]) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.helloFromC();
    }
}

C 部分:

/* ctest.c */

#include <jni.h>
#include <stdio.h>

JNIEXPORT void JNICALL Java_HelloWorld_helloFromC
  (JNIEnv * env, jobject jobj)
{
    printf("Hello from C!\n");
}

通过Cygwin,我成功了

javac HelloWorld.java
javah HelloWorld

创建这样的头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    helloFromC
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_helloFromC
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

到目前为止一切顺利。我还可以使用以下命令编译 C 程序:

$ gcc -D __int64="long long" -shared -I"D:\Programy\Java\JDK 8u31\include" 
-I"D:\Programy\Java\JDK 8u31\include\win32" ctest.c -o ctest.dll

现在我应该可以做到了

java HelloWorld 

查看 C 的输出,但我收到此错误:

$ java HelloWorld
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000018011ae47, pid=3156, tid=1176
#
# JRE version: Java(TM) SE Runtime Environment (8.0_31-b13) (build 1.8.0_31-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.31-b07 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [cygwin1.dll+0xdae47]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# D:\Dokumenty\Fifth\src\hs_err_pid3156.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

我试过的:

  1. 编译时使用-mno-cygwin标志,但由于我安装了最新版本的Cygwin,它不再被支持。

  2. 使用 -mno-cygwin 标志和 gcc-3 而不是 gcc - 但 Cygwin 不识别 gcc-3 命令。

  3. 正在添加环境变量。这似乎是常见的解决方案,但不知何故它对我不起作用。在我的系统上,Cygwin 安装在 D:\Programy\Cygwin,因此我添加到 PATH 的文件夹是 D:\Programy\Cygwin\bin,如 picture 所示(对不起外部 link , 我没有足够的声誉来 post 图片)。

从我读过的所有答案来看,这个 应该 有效,但它没有。 Cygwin 不是直接在 C:\Cygwin 中有问题吗?还是我做错了什么?我检查了文件夹,cygwin1.dll,它没有丢失。

我 运行 使用 Windows 8,64 位。 Cygwin 版本:1.7.35-1,安装了整个 Devel 包。 GCC 版本是 4.9.2.

抱歉这么长post,我只是想提供尽可能多的信息。我已经被这个问题困扰好几天了,很高兴收到任何建议。

编辑: 我刚刚注意到用 gcc 命令编译我的 C 文件并没有生成任何可执行文件,我觉得这很奇怪。它也不会抛出任何错误或警告。对此有什么想法吗?这会是我麻烦的根源吗?

编辑 2: 我刚刚发现这应该不是问题,我实际上是在制作库,而不是可执行文件。

编辑 3: 好吧,我放弃了。这似乎比我最初想象的要大得多。无法做到这一点的原因是 cygwin1.dll 无法动态加载,因为它在初始化时需要 4k 的底部堆栈字节是空闲的——如果它是从 JNI 调用的,这可能是个问题。 有一些方法可以克服它;如果您正在寻找解决方案,this post sums up nicely what needs to be done and this one 也很有用。对于我的项目,这不值得 - 但祝你好运。

在您的 c 文件中添加使用 javah 生成的头文件

/* ctest.c */
#include "HelloWorld.h"
#include <jni.h>
#include <stdio.h>

JNIEXPORT void JNICALL Java_HelloWorld_helloFromC
(JNIEnv * env, jobject jobj)
{
printf("Hello from C!\n");
}

和 运行 使用

java -Djava.library.path=. HelloWorld

如果不行就试试

java HelloWorld

this site

中解释了一个更详细的示例

由于我的声誉低无法发表评论,所以我会在那里说出来。

  1. cmd中echo %PATH%的结果是什么,你看清楚Cygwin的二进制文件的路径了吗?
  2. D:\Dokumenty\Fifth\src\hs_err_pid3156.logjava HelloWorld之后的日志内容是什么?

我会在你的之后编辑这个答案。

我发现无法做到这一点的原因是 cygwin1.dll 无法动态加载,因为它在初始化时需要 4k 底部堆栈字节空闲 - 如果它被调用,这可能是个问题来自 JNI。

一些方法可以克服它;如果您正在寻找解决方案,this post sums up nicely what needs to be done and this one can also be useful. I also found an explicit solution here.

我找到了解决这个问题的方法。 运行配置脚本时,使用

./configure --disable-static --enable-shared --host=x86_64-w64-mingw32

最后一个flag使用了Cygwin自带的mingw编译器。 Mingw 链接针对的是 Microsoft 的 msvcrt.dll 而不是 cygwin1.dll。