Cannot run C program from Java using Cygwin

烈酒焚心 提交于 2021-02-07 13:26:54

问题


I'm trying to make my first Java/C program using JNI. Here's how 'my' code looks - it's copied from this website:

/* 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 part:

/* ctest.c */

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

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

Through Cygwin, I succesfully did

javac HelloWorld.java
javah HelloWorld

to create a header file like this:

/* 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

So far so good. I can also compile the C program using:

$ 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

Now I should be able to do

java HelloWorld 

to see output from C, but instead I'm getting this error:

$ 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.
#

What I have tried:

  1. Using -mno-cygwin flag when compiling, but since I have the newest version of Cygwin installed, it's not supported anymore.

  2. Using -mno-cygwin flag with gcc-3 instead of gcc - but Cygwin doesn't recognize gcc-3 command.

  3. Adding an environment variable. This seems to be the common solution, but somehow it doesn't work for me. On my system, Cygwin is installed in D:\Programy\Cygwin, therefore the folder I added to PATH is D:\Programy\Cygwin\bin, as shown in the picture (sorry for external link, I don't have enough reputation to post pictures).

From all the answers I've read, this one should work, but it doesn't. Is there a problem with Cygwin not being directly in C:\Cygwin? Or am I doing something else wrong? I checked the folder and there is cygwin1.dll, it's not missing.

I'm running on Windows 8, 64-bit. Version of Cygwin: 1.7.35-1, installed the whole Devel package. GCC version is 4.9.2.

Sorry for the long post, I just wanted to provide as much information as I could. I've been stuck with this problem for several days now and will be glad for any advice.

Edit: I just noticed that compiling my C file with gcc command as above doesn't produce any executable file, which I find very strange. It also doesn't throw any error or warning. Any ideas on this one? Could that be the source of my trouble?

Edit 2: I just found out this should not be an issue, I'm actually making a library, not an executable file.

Edit 3: Okay, I'm giving up. It seems like much bigger issue than I initially thought it would be. The reason this cannot be done is that cygwin1.dll cannot be dynamically loaded, because it needs 4k of bottom stack bytes to be free when it's initializing - which might be a problem if it's being called from JNI. There are some ways to overcome it; if you're looking for a solution, this post sums up nicely what needs to be done and this one can also be useful. For my project, it's just not worth it - but good luck.


回答1:


I found that the reason this cannot be done is that cygwin1.dll cannot be dynamically loaded, because it needs 4k of bottom stack bytes to be free when it's initializing - which might be a problem if it's being called from JNI.

There are some ways to overcome it; if you're looking for a solution, this post sums up nicely what needs to be done and this one can also be useful. I also found an explicit solution here.




回答2:


add header file which was generated using javah in your c file

/* 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");
}

and run using

java -Djava.library.path=. HelloWorld

if it does not work than try

java HelloWorld

a much more detailed example is explained in this site




回答3:


As i can't comment with my low reputation i'll say it there.

  1. What is the result of echo %PATH% in cmd, do you clearly see the path to Cygwin's binaries ?
  2. What are the contents of the logs after java HelloWorld in D:\Dokumenty\Fifth\src\hs_err_pid3156.log ?

I'll edit this answer after yours.




回答4:


I figured out a solution to this problem. When running the configure script, use

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

The last flag uses the mingw compiler that comes packaged with Cygwin. Mingw links against Microsoft's msvcrt.dll rather that the cygwin1.dll.



来源:https://stackoverflow.com/questions/29487061/cannot-run-c-program-from-java-using-cygwin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!