博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
交叉编译总结笔记
阅读量:5254 次
发布时间:2019-06-14

本文共 5711 字,大约阅读时间需要 19 分钟。

  在项目的流程中,我们涉及到使用交叉编译的部分,关于这一块,我将研究后的结果总结如下。

 

  DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。

 

整体环境:

64位 Win7系统

jdk1.8.0_45

Eclipse-Mars

Visual Studio 2013

 

  首先,JAVA是无法直接调用C#的dll的,需要通过经过桥接的方式,我才用的方法是通过管理性的c++桥接的方式,帮助JAVA调用C#的dll。整体流程如下。

  

  整体的大概流程是:

    Java -> JNI -> C++ dll  <== Managed C++ ==> C# dll

  依照这个顺序来执行的话,第一步需要在JAVA中写好一个类,我们将其命名为TestJNI,这个类里面声明的函数最终将会由C#来实现:

public class TestJNI {

  public native void denoiseWord(String path,int trd);

  public native void cutwords(int trd, String analyzer);
  public native void key(String Path,int trd);
  public native void translate(int trd);

static {          System.loadLibrary("c++dll");     }      public static void main(String[] args) {          TestJNI t = new TestJNI();         System.out.println(System.getProperty("java.library.path"));    }  }

  在这里我声明了函数translate,这个函数在JAVA中不会被实现,他真正被实现的地方是在C#所写的dll中。

  在完成了JAVA部分的代码后,需要用javah命令产生.h文件,我是用的JAVA编译软件是eclipse,在工程目录下的bin文件夹内可以看到.class文件,打开命令行,输入

javah -classpath . -jni TestJNI

  正确执行指令之后,在当前文件夹内生成了这个类的.h文件。

  

/* DO NOT EDIT THIS FILE - it is machine generated */#include 
/* Header for class TestJNI */#ifndef _Included_TestJNI#define _Included_TestJNI#ifdef __cplusplusextern "C" {#endif/* * Class: TestJNI * Method: denoiseWord * Signature: (Ljava/lang/String;I)V */JNIEXPORT void JNICALL Java_TestJNI_denoiseWord (JNIEnv *, jobject, jstring, jint);/* * Class: TestJNI * Method: cutwords * Signature: (ILjava/lang/String;)V */JNIEXPORT void JNICALL Java_TestJNI_cutwords (JNIEnv *, jobject, jint, jstring);/* * Class: TestJNI * Method: key * Signature: (Ljava/lang/String;I)V */JNIEXPORT void JNICALL Java_TestJNI_key (JNIEnv *, jobject, jstring, jint);/* * Class: TestJNI * Method: translate * Signature: (I)V */JNIEXPORT void JNICALL Java_TestJNI_translate (JNIEnv *, jobject, jint);#ifdef __cplusplus}#endif#endif

  在这个.h头文件中,可以清楚地看到,在JAVA中声明的函数在这个头文件中被声明了。暂时跳过c++的部分,因为c++的作用是起到中间的桥梁的作用,真正的两边是JAVA和C#,所以我们先完成C#的部分,最后再来搭建中间的桥梁。

  创建一个C#控制台程序,在开始编程之前,在菜单栏中选择【项目】-》【设置】-》【应用】中将输出类型改为类库。

  

  完成C#部分对于函数的实现,编译成动态链接库。

  下一步就是C++部分。首先用VS2013创建一个C++编写类库的工程,首先承建一个C++的win32工程,在设置页面注意勾选:

  

  在编译C++DLL之前,需要做以下配置,在项目属性对话框中选择"C/C++"|"Advanced",将Compile AS 选项的值改为"C++"。在运行目录下,需要引入刚才C#编译完成的动态链接库,还有三个头文件分别是jni.h、jni_md.h和刚才通过javah指令生成的头文件,前两个文件可以从网上下载,在C++程序中引入这几样头文件,使用c#动态链接库的命名空间。

#include "stdafx.h"#include "c++dll.h"#include "jni.h" #include "jni_md.h"  #include "TestJNI.h"  #include 
#include "string.h"#include
#include
#include
//引入c#的库和命名空间 #using "ClassToDll.dll"using namespace ClassToDll;#using "mscorlib.dll"#using "System.dll"using namespace System;

  特别需要注意,选择《项目》-> 《属性页》->《配置属性》->《常规》->《公共语言运行库支持》,选择公共语言运行库支持(/clr)。

  由于可能会用到jstring和string之间的转换问题,所以需要自己实现以下几个函数,用来做到字符串格式之间的转换。

  

jstring stringTojstring(JNIEnv* env, const char* pat){    jclass strClass = env->FindClass("Ljava/lang/String;");    jmethodID ctorID = env->GetMethodID(strClass, "
", "([BLjava/lang/String;)V"); jbyteArray bytes = env->NewByteArray(strlen(pat)); env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat); jstring encoding = env->NewStringUTF("utf-8"); return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);}char* jstringTostring(JNIEnv* env, jstring jstr){ char* rtn = NULL; jclass clsstring = env->FindClass("java/lang/String"); jstring strencode = env->NewStringUTF("utf-8"); jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode); jsize alen = env->GetArrayLength(barr); jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE); if (alen > 0) { rtn = (char*)malloc(alen + 1); memcpy(rtn, ba, alen); rtn[alen] = 0; } env->ReleaseByteArrayElements(barr, ba, 0); return rtn;}String^ jstringToStr(JNIEnv* env, jstring jstr){ char* str = jstringTostring(env, jstr); String^ value = gcnew String(str); free(str); return value;}jstring strTojstring(JNIEnv* env, String^ rtn){ pin_ptr
wch = PtrToStringChars(rtn); size_t convertedChars = 0; size_t sizeInBytes = ((rtn->Length + 1) * 2); char *ch = (char *)malloc(sizeInBytes); errno_t err = wcstombs_s(&convertedChars, ch, sizeInBytes, wch, sizeInBytes); jstring js = stringTojstring(env, ch); free(ch); return js;}

  之后,根据javah生成头文件中的函数声明,依次实现各个函数。

JNIEXPORT void JNICALL Java_TestJNI_denoiseWord(JNIEnv *env, jobject obj, jstring path, jint trd){    //c#中的对象     Denoise ^d = gcnew Denoise();    d->denoiseWord(jstringToStr(env, path),(int)trd);}JNIEXPORT void JNICALL Java_TestJNI_cutwords(JNIEnv *env, jobject obj, jint trd ,jstring){    Denoise ^d = gcnew Denoise();    d->cutwords((int)trd, "Lucene.China.ChineseAnalyzer");}JNIEXPORT void JNICALL Java_TestJNI_key(JNIEnv *env, jobject,  jstring Path ,jint trd){    Denoise ^d = gcnew Denoise();    d->key( jstringToStr(env, Path),(int)trd);}JNIEXPORT void JNICALL Java_TestJNI_translate(JNIEnv *env, jobject, jint trd){    Denoise ^d = gcnew Denoise();    d->translate((int)trd);}

  将c++工程进行编译,得到c++的动态链接库。

  回到JAVA程序,我特意在最开始留了一句

System.out.println(System.getProperty("java.library.path"));

  用来输出library.path的地址,在这个地址下,将刚才编译好的C++,C#和其他用到的动态链接库放在这个文件夹下,运行JAVA程序,就可以使用JAVA调用c#编写的动态链接库了。

 

报错处理:

  如果出现如下报错

  一般是因为没有把库放在正确的路径下面,或者缺少依赖的库,补上后可以消除这个问题。

 

  如果出现如下报错

  这个是JAVA虚拟机内部错误,一般问题是出在了C#运行中出现的错误,由于C#和JAVA中string的编码格式不同,所以使用命令行输出会出现输出乱码的问题,推荐将错误信息输出到文件,这样可以看到C#里面出错的部分在哪里。

 

 

  

 

 

转载于:https://www.cnblogs.com/R-81/p/6250970.html

你可能感兴趣的文章