从 Java 调用 c 函数

发布于 2024-11-06 06:28:42 字数 101 浏览 1 评论 0原文

如何从 Java 调用 C 函数。 看来c是基于编译器的。

我想从Java调用Windows中的C函数,并且 GCC 函数也来自 Java。

有什么参考吗?

How to call c function from Java.
Seems c is compiler based.

I would like to call C function in Windows from Java, and
GCC function fron Java too.

Any reference?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

陈年往事 2024-11-13 06:28:42

看看 Java 本机接口:入门

2.1 概述

[...] 编写一个简单的 Java 应用程序,调用 C 函数进行打印
“你好世界!”。该过程包括以下步骤:

创建一个声明本机方法的类 (HelloWorld.java)。使用
javac 编译 HelloWorld 源文件,生成该类
文件HelloWorld.class。 javac 编译器随 JDK 或 Java 一起提供
2 个 SDK 版本。使用javah -jni生成C头文件
(HelloWorld.h) 包含本机方法的函数原型
执行。 javah 工具随 JDK 或 Java 2 SDK 提供
发布。编写本机的 C 实现 (HelloWorld.c)
方法。将 C 实现编译为本机库,创建
Hello-World.dlllibHello-World.so。使用 C 编译器和链接器
在主机环境上可用。使用以下命令运行 HelloWorld 程序
java运行时解释器。两个类文件 (HelloWorld.class)
并加载本机库(HelloWorld.dlllibHelloWorld.so
在运行时。本章的其余部分解释了这些步骤
详细信息。

2.2 声明本机方法

您首先在 Java 编程中编写以下程序
语言。该程序定义了一个名为 HelloWorld 的类,其中包含
本机方法,打印。

class HelloWorld {
    私有本机无效打印();

    公共静态无效主(字符串[] args){
        新的HelloWorld().print();
    }

    静止的 {
        System.loadLibrary("HelloWorld");
    }
}

HelloWorld 类定义以 print 本机方法的声明开始。接下来是一个主要方法
实例化 Hello-World 类并调用 print 本机方法
对于这个例子。类定义的最后一部分是静态的
加载包含以下内容的本机库的初始化程序
打印本机方法的实现。

原生方法的声明有两点不同
例如 print 以及 Java 中常规方法的声明
编程语言。本机方法声明必须包含
本机修饰符。 native 修饰符表明该方法是
用另一种语言实现。另外,本机方法声明
以分号结束,语句终止符符号,
因为类中没有本地方法的实现
本身。我们将在单独的 C 文件中实现 print 方法。

在调用本机方法 print 之前,本机库
必须加载实现打印。在这种情况下,我们加载原生
HelloWorld 类的静态初始化程序中的库。爪哇
虚拟机在之前自动运行静态初始化程序
调用 HelloWorld 类中的任何方法,从而确保
在调用打印本机方法之前加载本机库。

我们定义一个 main 方法来运行 HelloWorld 类。
Hello-World.main 以与以下相同的方式调用本机方法 print
它会调用常规方法。

System.loadLibrary 采用库名称,定位一个本机库
对应于该名称,并将本机库加载到
应用。我们将在稍后讨论具体的加载过程
书。现在只需记住,为了
System.loadLibrary("HelloWorld") 要成功,我们需要创建一个
本机库在 Win32 上称为 HelloWorld.dll,或在 Win32 上称为 libHelloWorld.so
索拉里斯。

2.3 编译HelloWorld类

定义完 HelloWorld 类后,将源代码保存在
文件名为 HelloWorld.java。然后使用编译源文件
JDK 或 Java 2 SDK 版本附带的 javac 编译器:

 javac HelloWorld.java

此命令将生成一个 HelloWorld.class
文件位于当前目录中。

2.4 创建本机方法头文件

接下来我们将使用javah工具生成JNI风格的头文件
这在用 C 实现本机方法时很有用。您可以运行
Hello-World 类上的 javah 如下:

<前><代码> javah -jni HelloWorld

头文件的名称就是类名
其末尾附加了“.h”。上面显示的命令
生成一个名为 HelloWorld.h 的文件。我们不会列出生成的
完整的头文件在这里。最重要的部分
头文件是Java_HelloWorld_print的函数原型,其中
是实现HelloWorld.print方法的C函数:

 JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);

暂时忽略 JNIEXPORTJNICALL 宏。您可能已经注意到
本机方法的 C 实现接受两个参数
即使本机方法的相应声明接受
没有争论。每个本机方法的第一个参数
实现是一个 JNIEnv 接口指针。第二个参数是
HelloWorld 对象本身的引用(有点像“this
C++ 中的指针)。我们将讨论如何使用 JNIEnv 接口
指针和 jobobject 参数将在本书后面介绍,但是这个简单
示例忽略两个参数。

2.5 编写Native方法实现

javah生成的JNI风格的头文件可以帮助你编写C或
本机方法的 C++ 实现。你写的函数
必须遵循生成的头文件中指定的 -prototype。你
可以在 C 文件 HelloWorld.c 中实现 Hello-World.print 方法,如下所示
如下:

#include ;
#include ;
#include“HelloWorld.h”   

JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) {
     printf("你好世界!\n");
     返回;
}

这个本机方法的实现很简单。它使用 printf 函数显示字符串“Hello World!”然后返回。如前所述,JNIEnv 指针和对象引用这两个参数都将被忽略。

C程序包含三个头文件:

jni.h -- 此头文件提供本机代码所需的信息
调用 JNI 函数。编写本机方法时,您必须始终
将此文件包含在您的 C 或 C++ 源文件中。
stdio.h——代码
上面的代码片段还包含 stdio.h 因为它使用 printf
功能。
HelloWorld.h -- 您使用生成的头文件
javah。它包括 Java_HelloWorld_print 的 C/C++ 原型
功能。
2.6 编译C源代码并创建原生库

请记住,当您在
HelloWorld.java 文件中,您包含了一行加载本机的代码
库到程序中:

 System.loadLibrary("HelloWorld");   

现在所有必要的 C 代码
编写完成后,您需要编译 Hello-World.c 并构建此本机
图书馆。

不同的操作系统支持不同的原生构建方式
图书馆。在 Solaris 上,以下命令构建共享库
名为 libHello-World.so:

<预><代码> cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so

-G 选项指示 C 编译器生成共享库而不是常规 Solaris
可执行文件。由于本书页宽的限制,
我们将命令行分成两行。你需要输入命令
在一行中,或将命令放在脚本文件中。在 Win32 上,
以下命令构建动态链接库(DLL)HelloWorld.dll
使用 Microsoft Visual C++ 编译器:

 cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll 

-MD 选项确保 HelloWorld.dllWin32 多线程 C 库链接。
-LD 选项指示 C 编译器生成 DLL 而不是
常规 Win32 可执行文件。当然,在 Solaris 和 Win32 上您
需要放入反映您自己的设置的包含路径
机器。

2.7 运行程序

此时,您已准备好运行该程序的两个组件。
类文件 (HelloWorld.class) 调用本机方法,并且
本机库 (Hello-World.dll) 实现本机方法。

因为HelloWorld类包含它自己的main方法,所以你可以运行
Solaris或Win32上的程序如下:

 java HelloWorld

您应该看到以下输出:

<前><代码>你好世界!

设置您的本机库路径很重要
正确运行您的程序。本机库路径是一个列表
Java 虚拟机加载时搜索的目录数
本机库。如果您没有设置本机库路径
正确的话,您会看到类似于以下内容的错误:

 java.lang.UnsatisfiedLinkError:库路径中没有 HelloWorld
         在 java.lang.Runtime.loadLibrary(Runtime.java)
         在 java.lang.System.loadLibrary(System.java)
         在HelloWorld.main(HelloWorld.java) 

确保本机库位于本机库路径中的目录之一中。
如果您在 Solaris 系统上运行,则 LD_LIBRARY_PATH
环境变量用于定义本机库路径。制作
确保它包含包含该文件的目录的名称
libHelloWorld.so 文件。如果libHelloWorld.so文件在当前
目录中,您可以在标准中发出以下两个命令
shell (sh) 或 KornShell (ksh) 设置LD_LIBRARY_PATH
正确的环境变量:

<前><代码> LD_LIBRARY_PATH=。
导出LD_LIBRARY_PATH

等效命令
C shell(csh 或 tcsh)如下:

 setenv LD_LIBRARY_PATH 。

如果您运行的是 Windows 95 或
Windows NT机器,确保HelloWorld.dll在当前
目录,或 PATH 环境中列出的目录中
变量。

在Java 2 SDK 1.2版本中,您还可以指定本机库
java 命令行上的路径作为系统属性如下:

<代码> java -Djava.library.path=.你好世界

-D”命令行选项
设置 Java 平台系统属性。设置java.library.path
属性为“.”指示Java虚拟机搜索
当前目录中的本机库。

Have a look at Java Native Interface: Getting Started.

2.1 Overview

[...] write a simple Java application that calls a C function to print
"Hello World!". The process consists of the following steps:

Create a class (HelloWorld.java) that declares the native method. Use
javac to compile the HelloWorld source file, resulting in the class
file HelloWorld.class. The javac compiler is supplied with JDK or Java
2 SDK releases. Use javah -jni to generate a C header file
(HelloWorld.h) containing the function prototype for the native method
implementation. The javah tool is provided with JDK or Java 2 SDK
releases. Write the C implementation (HelloWorld.c) of the native
method. Compile the C implementation into a native library, creating
Hello-World.dll or libHello-World.so. Use the C compiler and linker
available on the host environment. Run the HelloWorld program using
the java runtime interpreter. Both the class file (HelloWorld.class)
and the native library (HelloWorld.dll or libHelloWorld.so) are loaded
at runtime. The remainder of this chapter explains these steps in
detail.

2.2 Declare the Native Method

You begin by writing the following program in the Java programming
language. The program defines a class named HelloWorld that contains a
native method, print.

class HelloWorld {
    private native void print();

    public static void main(String[] args) {
        new HelloWorld().print();
    }

    static {
        System.loadLibrary("HelloWorld");
    }
}

The HelloWorld class definition begins with the declaration of the print native method. This is followed by a main method that
instantiates the Hello-World class and invokes the print native method
for this instance. The last part of the class definition is a static
initializer that loads the native library containing the
implementation of the print native method.

There are two differences between the declaration of a native method
such as print and the declaration of regular methods in the Java
programming language. A native method declaration must contain the
native modifier. The native modifier indicates that this method is
implemented in another language. Also, the native method declaration
is terminated with a semicolon, the statement terminator symbol,
because there is no implementation for native methods in the class
itself. We will implement the print method in a separate C file.

Before the native method print can be called, the native library that
implements print must be loaded. In this case, we load the native
library in the static initializer of the HelloWorld class. The Java
virtual machine automatically runs the static initializer before
invoking any methods in the HelloWorld class, thus ensuring that the
native library is loaded before the print native method is called.

We define a main method to be able to run the HelloWorld class.
Hello-World.main calls the native method print in the same manner as
it would call a regular method.

System.loadLibrary takes a library name, locates a native library that
corresponds to that name, and loads the native library into the
application. We will discuss the exact loading process later in the
book. For now simply remember that in order for
System.loadLibrary("HelloWorld") to succeed, we need to create a
native library called HelloWorld.dll on Win32, or libHelloWorld.so on
Solaris.

2.3 Compile the HelloWorld Class

After you have defined the HelloWorld class, save the source code in a
file called HelloWorld.java. Then compile the source file using the
javac compiler that comes with the JDK or Java 2 SDK release:

 javac HelloWorld.java

This command will generate a HelloWorld.class
file in the current directory.

2.4 Create the Native Method Header File

Next we will use the javah tool to generate a JNI-style header file
that is useful when implementing the native method in C. You can run
javah on the Hello-World class as follows:

  javah -jni HelloWorld

The name of the header file is the class name
with a ".h" appended to the end of it. The command shown above
generates a file named HelloWorld.h. We will not list the generated
header file in its entirety here. The most important part of the
header file is the function prototype for Java_HelloWorld_print, which
is the C function that implements the HelloWorld.print method:

 JNIEXPORT void JNICALL   Java_HelloWorld_print (JNIEnv *, jobject);

Ignore the JNIEXPORT and JNICALL macros for now. You may have noticed
that the C implementation of the native method accepts two arguments
even though the corresponding declaration of the native method accepts
no arguments. The first argument for every native method
implementation is a JNIEnv interface pointer. The second argument is a
reference to the HelloWorld object itself (sort of like the "this"
pointer in C++). We will discuss how to use the JNIEnv interface
pointer and the jobject arguments later in this book, but this simple
example ignores both arguments.

2.5 Write the Native Method Implementation

The JNI-style header file generated by javah helps you to write C or
C++ implementations for the native method. The function that you write
must follow the -prototype specified in the generated header file. You
can implement the Hello-World.print method in a C file HelloWorld.c as
follows:

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

JNIEXPORT void JNICALL   Java_HelloWorld_print(JNIEnv *env, jobject obj)  {
     printf("Hello World!\n");
     return;
}

The implementation of this native method is straightforward. It uses the printf function to display the string "Hello World!" and then returns. As mentioned before, both arguments, the JNIEnv pointer and the reference to the object, are ignored.

The C program includes three header files:

jni.h -- This header file provides information the native code needs
to call JNI functions. When writing native methods, you must always
include this file in your C or C++ source files.
stdio.h -- The code
snippet above also includes stdio.h because it uses the printf
function.
HelloWorld.h -- The header file that you generated using
javah. It includes the C/C++ prototype for the Java_HelloWorld_print
function.
2.6 Compile the C Source and Create a Native Library

Remember that when you created the HelloWorld class in the
HelloWorld.java file, you included a line of code that loaded a native
library into the program:

 System.loadLibrary("HelloWorld");   

Now that all the necessary C code
is written, you need to compile Hello-World.c and build this native
library.

Different operating systems support different ways to build native
libraries. On Solaris, the following command builds a shared library
called libHello-World.so:

 cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so

The -G option instructs the C compiler to generate a shared library instead of a regular Solaris
executable file. Because of the limitation of page width in this book,
we break the command line into two lines. You need to type the command
in a single line, or place the command in a script file. On Win32, the
following command builds a dynamic link library (DLL) HelloWorld.dll
using the Microsoft Visual C++ compiler:

 cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll 

The -MD option ensures that HelloWorld.dll is linked with the Win32 multithreaded C library.
The -LD option instructs the C compiler to generate a DLL instead of a
regular Win32 executable. Of course, on both Solaris and Win32 you
need to put in the include paths that reflect the setup on your own
machine.

2.7 Run the Program

At this point, you have the two components ready to run the program.
The class file (HelloWorld.class) calls a native method, and the
native library (Hello-World.dll) implements the native method.

Because the HelloWorld class contains its own main method, you can run
the program on Solaris or Win32 as follows:

 java HelloWorld

You should see the following output:

   Hello World! 

It is important to set your native library path
correctly for your program to run. The native library path is a list
of directories that the Java virtual machine searches when loading
native libraries. If you do not have a native library path set up
correctly, then you see an error similar to the following:

 java.lang.UnsatisfiedLinkError: no HelloWorld in library path
         at java.lang.Runtime.loadLibrary(Runtime.java)
         at java.lang.System.loadLibrary(System.java)
         at HelloWorld.main(HelloWorld.java) 

Make sure that the native library resides in one of the directories in the native library path.
If you are running on a Solaris system, the LD_LIBRARY_PATH
environment variable is used to define the native library path. Make
sure that it includes the name of the directory that contains the
libHelloWorld.so file. If the libHelloWorld.so file is in the current
directory, you can issue the following two commands in the standard
shell (sh) or KornShell (ksh) to set up the LD_LIBRARY_PATH
environment variable properly:

 LD_LIBRARY_PATH=.
 export LD_LIBRARY_PATH

The equivalent command in
the C shell (csh or tcsh) is as follows:

 setenv LD_LIBRARY_PATH .

If you are running on a Windows 95 or
Windows NT machine, make sure that HelloWorld.dll is in the current
directory, or in a directory that is listed in the PATH environment
variable.

In Java 2 SDK 1.2 release, you can also specify the native library
path on the java command line as a system property as follows:

 java -Djava.library.path=. HelloWorld

The "-D" command-line option
sets a Java platform system property. Setting the java.library.path
property to "." instructs the Java virtual machine to search for
native libraries in the current directory.

揪着可爱 2024-11-13 06:28:42

简而言之,只需确保加载包含函数定义的相关库,加载遵循 JNI 规范的库并包装第一个库中的目标函数,公开 Java 类中的本机方法,然后就可以开始了。

我建议不要使用原始 JNI,因为它包含大量样板代码,如果您开始包装一个 C 库,您最终会诅咒自己。无论如何,在开始时请随意涉足 JNI,但在实际工作中请使用诸如 JNA 之类的东西。

In simple terms, just make sure you load the relevant library which contains the function definition, load the library which follows the JNI specification and wraps the target function from the first library, expose native methods from your Java class and you should be good to go.

I'd recommend against raw JNI since it contains a lot of boilerplate code and you would end up cursing yourself if you start wrapping a big C library. By all means do feel free to dabble in JNI when starting out but use something like JNA when it comes to real work.

友欢 2024-11-13 06:28:42

您的选项包括:

Java 本机接口
请参阅:https://en.wikipedia.org/wiki/Java_Native_Interface

引用:

JNI 使程序员能够编写本机方法来处理应用程序无法完全用 Java 编程语言编写的情况,例如,当标准 Java 类库不支持特定于平台的功能或程序库时

Java Native Access

请参阅:https://en.wikipedia.org/wiki/Java_Native_Access

引用:

Java Native Access 是一个社区开发的库,它使 Java 程序无需使用 Java Native Interface 即可轻松访问本机共享库。

JNR-FFI

请参阅:https://github.com/jnr/jnr-ffi引用


jnr-ffi 是一个 Java 库,用于加载本机库,无需手动编写 JNI 代码或使用 SWIG 等工具。

You options include:

Java Native Interface
see: https://en.wikipedia.org/wiki/Java_Native_Interface

quote:

JNI enables programmers to write native methods to handle situations when an application cannot be written entirely in the Java programming language, e.g. when the standard Java class library does not support the platform-specific features or program library

Java Native Access

see: https://en.wikipedia.org/wiki/Java_Native_Access

quote:

Java Native Access is a community-developed library that provides Java programs easy access to native shared libraries without using the Java Native Interface.

JNR-FFI

see: https://github.com/jnr/jnr-ffi

quote:

jnr-ffi is a java library for loading native libraries without writing JNI code by hand, or using tools such as SWIG.

み格子的夏天 2024-11-13 06:28:42

在“异国情调”类别中,请参阅 NestedVM,它将 C 编译为 Mips,并运行 Mips
JVM 内的虚拟机。

http://nestedvm.ibex.org/

In the "exotic" category, see NestedVM, which compiles the C to Mips, and runs a Mips
VM inside JVM.

http://nestedvm.ibex.org/

﹉夏雨初晴づ 2024-11-13 06:28:42

检查 JNAerator。
https://code.google.com/p/jnaerator/

您需要提供源代码代码和预处理器定义等

Checkout JNAerator.
https://code.google.com/p/jnaerator/

You need to provide the source code and preprocessor definitions etc.

可遇━不可求 2024-11-13 06:28:42

如果您使用的是 Windows 和 MinGW gcc,如果您在 lib 中遇到特定方法的 UnsatisfiedLinkError,则可能需要额外的标志:

gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"%JAVA_HOME%"\include -I"%JAVA_HOME%"\include\win32 BestCode.c -shared -o BestCode.dll

If you are using Windows and MinGW gcc you may need additional flag if you are getting UnsatisfiedLinkError for specific method in lib:

gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"%JAVA_HOME%"\include -I"%JAVA_HOME%"\include\win32 BestCode.c -shared -o BestCode.dll
娇妻 2024-11-13 06:28:42

@Jonas 给出了一个非常详细的答案,但我认为它也确实值得检查这个网站,你会得到所有重要的答案那里:

https://personal.ntu.edu.sg/ehchua/programming/java/javanativeinterface.html

它解释了如何使用 JNI 调用程序:

  • 对于 C 和 C++ 语言或两种语言的混合,
  • 没有 JNI任何参数、基元、字符串或基元数组
  • 访问对象变量、回调实例方法等等。

@Jonas gave a very elaborated answer, but I think its also really worth checking this website and you will get all your essential answers there:

https://personal.ntu.edu.sg/ehchua/programming/java/javanativeinterface.html

It explains how to call a program using JNI:

  • For languages C and C++ or a mixture of both
  • JNI without any parameters, primitives, strings or Array of primitives
  • Accessing object variables, callback instances methods and much more.
等往事风中吹 2024-11-13 06:28:42

我找到了解决这个问题的方法。您需要确保使用 64 位 C++ 编译器来编译代码,以调用在 64 位 JRE 上运行的 java 函数。与此同时,我们需要将创建的dll文件的路径保存在“环境变量”下的“路径”中。

I got a solution for this problem. What you need to ensure is you're compiling the code using 64-bit c++ compiler for calling java function running on 64-bit JRE. Along with it we need to save the path of created dll file in "Path" under "Environment variable".

A君 2024-11-13 06:28:42

首先确保通过在属性 java.library.path 设置路径来加载类路径中的本机库或 .dll 文件

,然后使用 System.loadLibrary()

Do not use .dll extension at the end.

First make ensure to load your native library or .dll file in class path by setting path at property java.library.path

Then use System.loadLibrary()

Do not use .dll extension at the end.
匿名。 2024-11-13 06:28:42

为了使 64 位兼容 dll 从下面的语句中删除“-MD”选项

cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll

For making 64-bit compatible dll Remove "-MD" option from statement below

cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文