gpt4 book ai didi

java - 如何在 Linux 和 eclipse 中为 JNI 配置创建 makefile

转载 作者:太空宇宙 更新时间:2023-11-04 03:46:53 25 4
gpt4 key购买 nike

我已经仔细按照 JNI 教程 here为了使用一些与磁带驱动器一起运行的 native 功能。因此,我想创建一个使用这些 native 库打开磁带的 Java 程序。

为了实现我的目标,我在 Linux 12.04 上使用 Eclipse Kepler CDT

下面我提到完成的步骤:

首先,我有三个 Java 类:

TestTape
BasicTapeDevice
LogicalEOMException

最后是我的 TapeLinux.c 文件

TestTape 包含主要功能。

public class TestTape {

public static void main(String[] args) throws IOException {


BasicTapeDevice d = new BasicTapeDevice("/dev/nst0");

System.out.print("Rewinding...");
System.out.flush();
d.rewind();
System.out.println("done!");

System.out.print("Spacing to end of data...");
System.out.flush();
d.spaceEOD();
System.out.println("done!");
}

}

在具有这些 native 函数的 Java 实现的 BasicTapeDevice 类下面:

class BasicTapeDevice {

private FileDescriptor fd;
private InputStream in;
private OutputStream out;
private boolean eof;
private boolean eom;
private boolean ignoreEOM;

public BasicTapeDevice(String pathName) throws IOException {
fd = new FileDescriptor();
tapeOpen(pathName);
in = new TapeInputStream();
out = new TapeOutputStream();
eof = false;
eom = false;
ignoreEOM = false;
}
public synchronized void close() throws IOException {
if (fd != null) {
try {
if (fd.valid()) {
tapeClose();
}
} finally {
fd = null;
}
}
}
public InputStream getInputStream() throws IOException {
ensureOpen();
return in;
}
public OutputStream getOutputStream() throws IOException {
ensureOpen();
return out;
}
public int getBlockSize() throws IOException {
ensureOpen();
return tapeGetBlockSize();
}
public void setBlockSize(int bs) throws IOException {
ensureOpen();
tapeSetBlockSize(bs);
}
public void rewind() throws IOException {
ensureOpen();
tapeRewind();
}
public void spaceEOD() throws IOException {
ensureOpen();
tapeSpaceEOD();
}
public void clearEOF() throws IOException {
ensureOpen();
if (eof) {
eof = false;
/* assume that the file mark has already been skipped */
} else {
throw new IOException("not at end of file");
}
}
public void clearEOM() throws IOException {
ensureOpen();

if (eom) {
ignoreEOM = true;
} else {
throw new IOException("not at logical end of media");
}
}
class TapeInputStream extends InputStream {
private byte[] temp = new byte[1];
public int read() throws IOException {
int n = read(temp, 0, 1);
if (n <= 0) {
return -1;
}
return temp[0] & 0xff;
}
public int read(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
}
if (off < 0 || len < 0 || off+len > b.length) {
throw new IndexOutOfBoundsException();
}
if (len == 0) {
return 0;
}
if (eof) {
return -1;
}
ensureOpen();
int n = tapeRead(b, off, len);
if (n <= 0) {
return -1;
}
return n;
}
public long skip(long numbytes) throws IOException {
return 0;
}
public void close() throws IOException {
BasicTapeDevice.this.close();
}
}
class TapeOutputStream extends OutputStream {

private byte[] temp = new byte[1];

public void write(int b) throws IOException {
temp[0] = (byte) b;
write(temp, 0, 1);
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();

}
if (off < 0 || len < 0 || off+len > b.length) {
throw new IndexOutOfBoundsException();
}
if (eom && !ignoreEOM) {
throw new LogicalEOMException("logical end-of-media");
}
int n = tapeWrite(b, off, len);
while (n < len) {
n += tapeWrite(b, off + n, len - n);
}
}
public void close() throws IOException {
BasicTapeDevice.this.close();
}
}
protected void finalize() {
try {
close();
} catch (IOException ex) {
}
}
private void ensureOpen() throws IOException {
if (fd == null || !fd.valid()) {
throw new IOException("tape device is not open");
}
}
private static native void initFields();
private native void tapeOpen(String pathName) throws IOException;
private native void tapeClose() throws IOException;
private native int tapeRead(byte[] b, int off, int len) throws IOException;
private native int tapeWrite(byte[] b, int off, int len) throws IOException;
private native int tapeGetBlockSize() throws IOException;
private native void tapeSetBlockSize(int bs) throws IOException;
private native void tapeRewind() throws IOException;
private native void tapeSpaceEOD() throws IOException;

/* load the JNI library specific for this platform */
static {
StringBuffer buf = new StringBuffer("Tape");
String osName = System.getProperty("os.name");
if (osName.equals("Windows NT") || osName.equals("Windows 2000")) {
buf.append("WinNT");
} else {
buf.append(osName);
}
System.loadLibrary(buf.toString());
initFields();
}

您可能已经看到 BasicTapeDevice 类具有 System.loadLibrary(),它应该导入我将要创建的 .so 库。

最后,最后一个类是LogicalEOMException:

class LogicalEOMException extends IOException {

public LogicalEOMException() {
super();
}
public LogicalEOMException(String s) {
super(s);
}
}

TapeLinux.c 下面

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/mtio.h>

#include <jni.h>

#include "BasicTapeDevice.h"

#define TRUE 1
#define FALSE 0


/* field IDs for commonly used object fields */
static jfieldID td_fdID;
static jfieldID td_eofID;
static jfieldID td_eomID;
static jfieldID IO_fd_fdID;


/* forward reference for utility functions */
static int getFD(JNIEnv* env, jobject obj);
static void setFD(JNIEnv* env, jobject obj, int fd);
static void throw(JNIEnv* env, int err);

/*
* Class: BasicTapeDevice
* Method: initFields
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_BasicTapeDevice_initFields
(JNIEnv *env, jclass cls)
{
/* retrieve field IDs for the fd, eof, and eom member variables */
td_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;");
td_eofID = (*env)->GetFieldID(env, cls, "eof", "Z");
td_eomID = (*env)->GetFieldID(env, cls, "eom", "Z");

/* retrieve the field ID for the private fd member of FileDescriptor */
cls = (*env)->FindClass(env, "java/io/FileDescriptor");
IO_fd_fdID = (*env)->GetFieldID(env, cls, "fd", "I");
}

/*
* Class: BasicTapeDevice
* Method: tapeOpen
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_BasicTapeDevice_tapeOpen
(JNIEnv *env, jobject this, jstring path)
{
int fd;
const char* p;

p = (*env)->GetStringUTFChars(env, path, 0);
fd = open(p, O_RDWR);
(*env)->ReleaseStringUTFChars(env, path, p);

if (fd == -1) {
throw(env, errno);
}

setFD(env, this, fd);
}

/*
* Class: BasicTapeDevice
* Method: tapeClose
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_BasicTapeDevice_tapeClose
(JNIEnv *env, jobject this)
{
int fd = getFD(env, this);
if (close(fd) == -1) {
throw(env, errno);
}

fd = -1;
setFD(env, this, fd);
}


/*
* Class: BasicTapeDevice
* Method: tapeRead
* Signature: ([BII)I
*/
JNIEXPORT jint JNICALL Java_BasicTapeDevice_tapeRead
(JNIEnv *env, jobject this, jbyteArray buf, jint off, jint len)
{
int n, fd;
jbyte* bufp;

fd = getFD(env, this);
bufp = (*env)->GetByteArrayElements(env, buf, 0);
n = read(fd, &bufp[off], len);
(*env)->ReleaseByteArrayElements(env, buf, bufp, 0);

if (n < 0) {
throw(env, errno);
} else if (n == 0) {
(*env)->SetBooleanField(env, this, td_eofID, TRUE);
}

return n;
}

/*
* Class: BasicTapeDevice
* Method: tapeWrite
* Signature: ([BII)I
*/
JNIEXPORT jint JNICALL Java_BasicTapeDevice_tapeWrite
(JNIEnv *env, jobject this, jbyteArray buf, jint off, jint len)
{
int n, fd;
jbyte* bufp;

fd = getFD(env, this);
bufp = (*env)->GetByteArrayElements(env, buf, 0);
n = write(fd, &bufp[off], len);
(*env)->ReleaseByteArrayElements(env, buf, bufp, 0);

if (n < 0) {
throw(env, errno);
} else if (n == 0) {
(*env)->SetBooleanField(env, this, td_eomID, TRUE);
}

return n;
}


/*
* Class: BasicTapeDevice
* Method: tapeGetBlockSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_BasicTapeDevice_tapeGetBlockSize
(JNIEnv *env, jobject this)
{
int fd;
struct mtget mtget;
jint bs;

fd = getFD(env, this);
if (ioctl(fd, MTIOCGET, &mtget) == -1) {
throw(env, errno);
bs = -1;
} else {
bs = mtget.mt_dsreg & MT_ST_BLKSIZE_MASK;
}

return bs;
}

/*
* Class: BasicTapeDevice
* Method: tapeSetBlockSize
* Signature: ()I
*/
JNIEXPORT void JNICALL Java_BasicTapeDevice_tapeSetBlockSize
(JNIEnv *env, jobject this, jint bs)
{
int fd;
struct mtop mtop;

mtop.mt_op = MTSETBLK;
mtop.mt_count = bs;
fd = getFD(env, this);
if (ioctl(fd, MTIOCTOP, &mtop) == -1) {
throw(env, errno);
}
}


/*
* Class: BasicTapeDevice
* Method: tapeRewind
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_BasicTapeDevice_tapeRewind
(JNIEnv *env, jobject this)
{
int fd;
struct mtop mtop;

mtop.mt_op = MTREW;
mtop.mt_count = 1;
fd = getFD(env, this);
if (ioctl(fd, MTIOCTOP, &mtop) == -1) {
throw(env, errno);
}
}

/*
* Class: BasicTapeDevice
* Method: tapeSpaceEOD
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_BasicTapeDevice_tapeSpaceEOD
(JNIEnv* env, jobject this)
{
int fd;
struct mtop mtop;

mtop.mt_op = MTEOM;
mtop.mt_count = 1;
fd = getFD(env, this);
if (ioctl(fd, MTIOCTOP, &mtop) == -1) {
throw(env, errno);
}
}

/*
* Retrieves the internal file descriptor from the BasicTapeDevice object
*/
static int getFD(JNIEnv* env, jobject obj) {
jobject fdobj;

fdobj = (*env)->GetObjectField(env, obj, td_fdID);
return (*env)->GetIntField(env, fdobj, IO_fd_fdID);
}

/*
* Sets the internal file descriptor of the BasicTapeDevice object
*/
static void setFD(JNIEnv* env, jobject obj, int fd)
{
jobject fdobj = (*env)->GetObjectField(env, obj, td_fdID);
(*env)->SetIntField(env, fdobj, IO_fd_fdID, fd);
}

/*
* Throws a new IOException
*/
static void throw(JNIEnv* env, int err)
{
jclass cls = (*env)->FindClass(env, "java/io/IOException");
if (cls != NULL) {
(*env)->ThrowNew(env, cls, strerror(err));
}
}

鉴于此编程结构,我将开始实现我的程序:

1) 首先,我使用这三个类创建一个 Java 项目(名为 Tape),然后使用以下参数在 C/C++ 项目(添加 C/C++ 特性)中转换 BasicTapeDevice 类:

Convert to C or C++ Project: C Project
Toolchains: LinuxGCC
Project Type: Makefile Project

这将创建以下内容:

Eclipse View 1

目前看来一切正常。我现在创建一个名为 jni 的文件夹,并在其中创建一个名为 makefile 的文件。

生成文件

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

# $* matches the target filename without the extension
BasicTapeDevice.h : BasicTapeDevice.class
javah -classpath $(CLASS_PATH) $*

我为 makefile BasicTapeDevice.h 创建一个 make 目标,然后构建它结果如下:

**** Build of configuration Default for project Tape ****
make BasicTapeDevice.h
javah -classpath ../bin BasicTapeDevice

Build Finished (took 775ms)

Eclipse View 2

现在之前创建的 c 文件被放在 jni 文件夹中一个名为 TapeLinux.c 的文件中,现在可以创建库 .so(记住我们是在 Linux 下)

这是我创建的makefile

生成文件

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

all : TapeLinux.so

# $@ matches the target, $< matches the first dependancy
TapeLinux.so : TapeLinux.o
gcc -Wl,--add-stdcall-alias -shared -o $@ $<

# $@ matches the target, $< matches the first dependancy
TapeLinux.o : TapeLinux.c TapeLinux.h
gcc -I"/home/tanio/DevelopmentEnvironment/jdk1.7.0_51/include/linux" -I"/home/tanio/DevelopmentEnvironment/jdk1.7.0_51/include" -c $< -o $@

# $* matches the target filename without the extension
BasicTapeDevice.h : BasicTapeDevice.class
javah -classpath $(CLASS_PATH) $*

clean :
rm TapeLinux.h TapeLinux.o TapeLinux.so

不幸的是,我没有正确理解这部分,我被卡住了。

编译器给我这个问题:

**** Build of configuration Default for project Tape ****
make all
make: *** No rule to make target `all'. Stop.

Build Finished (took 74ms)

你能帮我找出问题出在哪里吗?

谢谢

编辑 MAKEFILE

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

all : BasicTapeDevice.so

# $@ matches the target, $< matches the first dependancy
BasicTapeDevice.so : BasicTapeDevice.o
gcc -Wl -shared -o $@ $<

# $@ matches the target, $< matches the first dependancy
BasicTapeDevice.o : TapeLinux.c BasicTapeDevice.h
gcc -I"/home/tanio/DevelopmentEnvironment/jdk1.7.0_51/include/linux" -I"/home/tanio/DevelopmentEnvironment/jdk1.7.0_51/include" -c $< -o $@

# $* matches the target filename without the extension
BasicTapeDevice.h : BasicTapeDevice.class
javah -classpath $(CLASS_PATH) $*

clean :
rm BasicTapeDevice.h BasicTapeDevice.o BasicTapeDevice.so

这个 makefile 可以正确编译,但是当我运行应用程序时出现错误,因为 main 不在 BasicTapeDevice 中

我是否需要分别编译每个类然后运行程序,还是将所有内容放在同一个类中更好?

最佳答案

谢谢大家的帮助我解决了修改makefile的问题

这里是结果

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

all : libTape.so

# $@ matches the target, $< matches the first dependancy
libTape.so : TapeJNI.o
gcc -shared -fpic -o $@ $<

# $@ matches the target, $< matches the first dependancy
TapeJNI.o : TapeJNI.c TapeJNI.h
gcc -fpic -I"/home/tanio/DevelopmentEnvironment/jdk1.7.0_51/include" -I"/home/tanio/DevelopmentEnvironment/jdk1.7.0_51/include/linux" -c $< -o $@

# $* matches the target filename without the extension
TapeJNI.h : TapeJNI.class
javah -classpath $(CLASS_PATH) $*

clean :
rm TapeJNI.h TapeJNI.o libTape.so

我已经用另一个名字编译了,如果不匹配请见谅

关于java - 如何在 Linux 和 eclipse 中为 JNI 配置创建 makefile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23612450/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com