DSRC 是一款 C++ 编写的 DNA 序列压缩工具。
准备
JNI(Java Native Interface)编译过程:
- 编写带有 natvie 方法的 java 类,如 DSRCImpl.java
- javac 编译 class 文件,DSRCImpl.class
- 使用 javah 生成头文件, package_DSRCImpl.h
- 编写 c/c++ 代码实现DSRCImpl.h 中的方法。
- 编译各个平台的动态链接库。
- 在 Java 项目中加载动态链接库。
其中最关键的是第4、5步,实现头文件方法,及编译各平台动态链接库。
通过 native 方法生成 .h 头文件
DSRCImpl.java 代码如下:
1 2 3 4 5 6 7 8
| package com.genedock.sdk.internal.compress;
public class DSRCImpl {
public native int decompress(String inputFile, String outputFile, int t);
public native int compress(String inputFile, String outputFile, int t, int m); }
|
编译出头文件:
生成的 com_genedock_sdk_internal_compress_DSRCImpl.h
文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <jni.h>
#ifndef _Included_com_genedock_sdk_internal_compress_DSRCImpl #define _Included_com_genedock_sdk_internal_compress_DSRCImpl #ifdef __cplusplus extern "C" { #endif
JNIEXPORT jint JNICALL Java_com_genedock_sdk_internal_compress_DSRCImpl_decompress (JNIEnv *, jobject, jstring, jstring, jint);
JNIEXPORT jint JNICALL Java_com_genedock_sdk_internal_compress_DSRCImpl_compress (JNIEnv *, jobject, jstring, jstring, jint, jint);
#ifdef __cplusplus } #endif #endif
|
实现头文件中的方法
我们需要调用 DSRC 代码来压缩和解压文件。先获取 DSRC 项目。
1
| git clone https://github.com/refresh-bio/DSRC.git
|
将上面生成的 .h 文件拷贝到项目中。我将它放在 /example/cpplib/
目录下。新建 dsrcimpl.cpp
实现头文件中的方法。如下(jstring 类型需要做转换):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include "com_genedock_sdk_internal_compress_DSRCImpl.h" #include <Dsrc.h>
JNIEXPORT jint JNICALL Java_com_genedock_sdk_internal_compress_DSRCImpl_decompress (JNIEnv *env, jobject obj, jstring inputFile, jstring outputFile, jint t) { using namespace dsrc::lib;
const char *inFilename_ = env->GetStringUTFChars(inputFile, 0); const char *outFilename_ = env->GetStringUTFChars(outputFile, 0);
try { DsrcModule dsrc; dsrc.Decompress(inFilename_, outFilename_); } catch (const DsrcException &e) { return -1; } env->ReleaseStringUTFChars(inputFile, 0); env->ReleaseStringUTFChars(outputFile, 0); return 0; }
JNIEXPORT jint JNICALL Java_com_genedock_sdk_internal_compress_DSRCImpl_compress (JNIEnv *env, jobject obj, jstring inputFile, jstring outputFile, jint t, jint m) { using namespace dsrc::lib;
const char *inFilename_ = env->GetStringUTFChars(inputFile, 0); const char *outFilename_ = env->GetStringUTFChars(outputFile, 0);
try { DsrcModule dsrc; dsrc.SetThreadsNumber(t);
switch (m) { case 2: dsrc.SetDnaCompressionLevel(3); dsrc.SetQualityCompressionLevel(2); dsrc.SetFastqBufferSizeMB(256); break; case 1: dsrc.SetDnaCompressionLevel(2); dsrc.SetQualityCompressionLevel(2); dsrc.SetFastqBufferSizeMB(64); break; case 0: dsrc.SetDnaCompressionLevel(0); dsrc.SetQualityCompressionLevel(0); dsrc.SetFastqBufferSizeMB(8); break; }
dsrc.Compress(inFilename_, outFilename_); } catch (const DsrcException &e) { return -1; }
env->ReleaseStringUTFChars(inputFile, 0); env->ReleaseStringUTFChars(outputFile, 0); return 0; }
|
编写好cpp文件,修改example/cpplib/
目录下的Makefile文件,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| all: example1 example2 dsrcimpl
INC_PATH = ../../include/dsrc LIB_PATH = ../../lib/ LIB_JNI_PATH = /System/Library/Frameworks/JavaVM.framework/Headers DSRC_LIB = -ldsrc
.cpp.o: $(CXX) $(CXXFLAGS) -c $< -o $@ -I$(INC_PATH) -I$(LIB_JNI_PATH)
example1: example1.o $(CXX) $(CXXFLAGS) -o $@ $? -L$(LIB_PATH) $(DSRC_LIB) $(DEP_LIBS) strip $@
example2: example2.o $(CXX) $(CXXFLAGS) -o $@ $? -L$(LIB_PATH) $(DSRC_LIB) $(DEP_LIBS) strip $@
dsrcimpl: dsrcimpl.o c++ -dynamiclib -o libdsrcjava.jnilib dsrcimpl.o -L../../lib/ -ldsrc
clean: -rm *.o -rm example1 -rm example2 -rm libdsrcjava.jnilib
|
编译各平台动态链接库
MacOS
在 DSRC 根目录执行如下命令:
1
| make -f Makefile.osx lib
|
结束后在 lib/
目录下的到 libdsrc.a
文件。进入 example/cpplib/
目录使用 make 命令编译指定目标:
如果顺利,此时在当前目录下已经生成了 libdsrcjava.jnilib
文件。
Ubuntu
修改 src/Makefile
文件 34 行,如下:
1
| $(CXX) $(CXXFLAGS) -c $< -o $@ -fPIC
|
在 DSRC 根目录执行编译命令
1
| make -f Makefile.c++11 lib
|
再进入 examples/cpplib/
目录执行如下命令,即可生成 dsrcjava.so 动态链接库文件。
1 2
| g++ -c dsrcimpl.cpp -o dsrcjava.o -I../../include/dsrc -I/usr/lib/jvm/java-8-oracle/include -I/usr/lib/jvm/java-8-oracle/include/linux g++ -O2 -m64 -DNDEBUG -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -Wall -std=c++11 -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -I../../include/dsrc -shared -o dsrcjava.so dsrcimpl.cpp -L../../lib/ -ldsrc -lpthread -fPIC
|
Windows
windows 需要编译 x86 和 x64 两个版本链接库。DSRC 默认不支持编译 32 位的类库。
DSRC 项目使用 Visual Studio 编译,所以在此我们也使用 Visual Studio 编译。安装好 Visual Studio 后双击打开 DSRC 根目录下 dsrc20-vs2k12.sln
文件即可导入项目。
在解决方案上右键,点击生成
即可编译。在 1
处选择 Release Lib
即可编译生成 .lib
静态类库。
X64 编译
在解决方案上右键 -> 添加 -> 新建项目。选择 windows 桌面 -> windows 桌面向导,输入名称后确定。应用类型选择 动态链接库
,取消预编译头。删除生成的头文件和源文件。将我们的头文件和 cpp 文件添加进来,如下:
添加引用,选择 dsrc20-vs2k12
,设置 dsrcjava 属性。修改 VC++ 目录 下 包含目录
和 引用目录
,分别添加 jdk 安装目录下的 include/、include/win32/ 和 lib/ 目录,如下:
![](https://s.eirture.cn/pics/屏幕快照 2017-09-26 下午4.25.46.png?r=50)
在 C/C++
中添加 附加包含目录
,指定 DSRC 中 include/dsrc 目录。在代码生成
中,修改运行库
为多线程(/MT)
此时再去编译即可。
X86 编译
首先需要为 DSRC 添加 win32 解决方案。进入配置管理器,在 dsrc20-vs2k12 平台中新建如下:
打开 src/QualityModelerProxy.h
文件,将 168-176 行修改如下:
1 2 3 4 5 6 7 8 9
| case 1: return new TQualityLossyOrderPositionalModeler<7, 1>(); case 2: return new TQualityLossyOrderPositionalModeler<7, 2>(); case 3: return new TQualityLossyOrderPositionalModeler<7, 3>(); case 4: return new TQualityLossyOrderPositionalModeler<7, 4>(); case 5: return new TQualityLossyOrderPositionalModeler<7, 5>(); case 6: return new TQualityLossyOrderPositionalModeler<7, 6>(); case 7: return new TQualityLossyOrderPositionalModeler<7, 7>(); case 8: return new TQualityLossyOrderPositionalModeler<7, 8>(); case 9: return new TQualityLossyOrderPositionalModeler<7, 9>();
|
如 64 位同样,添加 JDK 的 include 和 include/win32 及 DSRC/include/dsrc 包含目录。将 C/C++
-> 代码生成
中,修改运行库
为多线程调试(/MTd)
此时编译即可生成 32 位平台链接库。
参考
- 极客学院 wiki
- Visual Studio下包含多项目的解决方案及项目间引用
- Visual Studio中开发Jni dll库
- 使用JNI进行Java与C/C++语言混合编程(1)–在Java中调用C/C++本地库
- Ubuntu 使用Jni开发实例详解
- Windows、Linux、Mac OSX编译jni动态库
- Mac OS上编译JNI的动态库