JNI Javaからcppを呼び出してみる。
■まずはJavaでコード書きます
https://gist.github.com/masazdream/5560075
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package jp.sp.jni; | |
public class HelloWorldJNI { | |
static { | |
System.loadLibrary("HelloWorldJNI"); | |
} | |
public native String sayHelloWorld(); | |
public static void main(String[] args){ | |
HelloWorldJNI hello = new HelloWorldJNI(); | |
System.out.println(hello.sayHelloWorld()); | |
} | |
} |
■対応するCppファイルを書きます
https://gist.github.com/masazdream/5560082
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================ | |
// Name : HelloWorldJNI.cpp | |
// Author : | |
// Version : | |
// Copyright : Your copyright notice | |
// Description : Hello World in C++, Ansi-style | |
//============================================================================ | |
#include "jp_sp_jni_HelloWorldJNI.h" | |
JNIEXPORT jstring JNICALL | |
Java_jp_sp_jni_HelloWorldJNI_sayHelloWorld(JNIEnv *env, jobject obj){ | |
return env->NewStringUTF("Hello World"); | |
} |
■JavaとCppのコードから必要なヘッダファイルとSharedObjectを作成します
そのために今回はantを使用しますので、antからgccコンパイルする環境を作成します。
・ant-contribのバイナリをantのlibに配置
http://sourceforge.net/projects/ant-contrib/files/
・ant-xercesのバイナリを取得して、antoのlibに配置
http://xerces.apache.org/mirrors.cgi
・ant-cpptasksを作成する。
http://sourceforge.net/projects/ant-contrib/files/ant-contrib/cpptasks-1.0-beta5/
デフォルトでついてくるbuild.xmlに以下の対策を施して、実行するとjarが作成出来ます。
■対策
①javacタグにincludeAntRuntime="true"を設定します。
②ソースをコンパイルするJavaのバージョンに注意しないと警告が
うるさいので処理します。
A. java.sourceとjavac.targetには、コンパイルするJavaのバージョンを
設定しましょう。
B. jt.jarのパスを表すpathを作成して、javacのbootclasspathに指定します。
<path id="compile.boot.path">
<fileset dir="${java.home}/lib">
<include name="rt.jar" />
</fileset>
</path>
<javac ・・・
<bootclasspath refid="compile.boot.path" />
</javac>
■必要なパスを通す
③xercesのライブラリをクラスパスに追加する
<path id="compile.path">
<fileset dir="[最初のステップでjarを置いたディレクトリ]">
<include name="*.jar" />
</fileset>
</path>
<javac ・・・
<classpath refid="compile.path" />
</javac>
これでコンパイル出来ます。
target/lib/cpptasks.jarがあるので、ant本体のlibディレクトリに
コピーします。
> echo $ANT_HOME
でhomeを確認が出来たら、配下のlibにコピーします。
■antの記述を整えます。
javahでヘッダーファイル作成を記述します。
ccタスクでcppファイルをコンパイルします。
<taskdef resource="cpptasks.tasks">でccタスクを使用する準備が出来ますので、
以下のようにccタスクを記述します。
<cc link="shared" outfile="[soを出力するディレクトリ名]/[クラス名]" obj="[ヘッダーファイルを出力したディレクトリ]">
<includepath location="${env.JAVA_HOME}/include}" />
<includepath location="${env.JAVA_HOME}/include/linux" />
<fileset dir="[ヘッダーファイルを出力したディレクトリ]" includes="HelloWorldJNI.cpp" />
<libset libs="stdc++"> ←cppの場合は指定。CとCPPが混じっている場合には、cppファイルのみにantで実行出来ます。
</cc>
※outfileに指定したパスのファイル名をつかって、libhello.soなどの名前が決定されます。
最終的に以下の様なファイルになる。https://gist.github.com/masazdream/5560085
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
<!-- WARNING: Eclipse auto-generated file. | |
Any modifications will be overwritten. | |
To include a user specific buildfile here, simply create one in the same | |
directory with the processing instruction <?eclipse.ant.import?> | |
as the first entry and export the buildfile again. --> | |
<project basedir="." default="build" name="jni"> | |
<property environment="env" /> | |
<property name="ECLIPSE_HOME" value="../../eclipse" /> | |
<property name="debuglevel" value="source,lines,vars" /> | |
<property name="target" value="1.7" /> | |
<property name="source" value="1.7" /> | |
<path id="jni.classpath"> | |
<pathelement location="bin" /> | |
</path> | |
<target name="init"> | |
<mkdir dir="bin" /> | |
<copy includeemptydirs="false" todir="bin"> | |
<fileset dir="src"> | |
<exclude name="**/*.java" /> | |
</fileset> | |
</copy> | |
</target> | |
<target name="clean"> | |
<delete dir="bin" /> | |
</target> | |
<target depends="clean" name="cleanall" /> | |
<target depends="build-subprojects,build-project,makeh" name="build" /> | |
<target name="build-subprojects" /> | |
<target depends="init" name="build-project"> | |
<echo message="${ant.project.name}: ${ant.file}" /> | |
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}"> | |
<src path="src" /> | |
<classpath refid="jni.classpath" /> | |
</javac> | |
</target> | |
<property name="h_dir" location="/root/workspace/jni/jnih" /> | |
<target name="makeh"> | |
<taskdef resource="cpptasks.tasks" /> | |
<javah classpath="/root/workspace/jni/bin" class="jp.sp.jni.HelloWorldJNI" destdir="${h_dir}" /> | |
<cc link="shared" outfile="/root/workspace/jni/dist/HelloWorldJNI" objdir="${h_dir}"> | |
<includepath location="${env.JAVA_HOME}/include" /> | |
<includepath location="${env.JAVA_HOME}/include/linux" /> | |
<fileset dir="${h_dir}" includes="HelloWorldJNI.cpp" /> | |
<libset libs="stdc++" /> | |
</cc> | |
</target> | |
<target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects" /> | |
<target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler"> | |
<copy todir="${ant.library.dir}"> | |
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" /> | |
</copy> | |
<unzip dest="${ant.library.dir}"> | |
<patternset includes="jdtCompilerAdapter.jar" /> | |
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" /> | |
</unzip> | |
</target> | |
<target description="compile project with Eclipse compiler" name="build-eclipse-compiler"> | |
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" /> | |
<antcall target="build" /> | |
</target> | |
</project> |
■Javaの実行
soファイルの入ったディレクトリを環境変数「LD_LIBRARY_PATH」に指定してから実行します。
実行結果は、Hello World。
せっかくなのでcやcppで記述したファイルをドンドンJavaで実行していましょう。
0 件のコメント:
コメントを投稿