概要
JNAを使ってC言語を呼び出す方法をまとめました。
前準備
まず、JNAのライブラリをmavenなりbuild.sbtなりに追加します。
build.sbt
scalaVersion := "2.13.6"
libraryDependencies += "net.java.dev.jna" % "jna" % "5.9.0"
libraryDependencies += "net.java.dev.jna" % "jna-platform" % "5.9.0"
JavaからC言語を呼び出す
Hello World的なプログラム
C言語で共有ライブラリを作る
以下のようなプログラムを作成します。
hoge.c
#include <stdio.h>
void hoge() {
printf("ほげぇ\n");
}
そして、以下のコマンドで共有ライブラリを作成します。
gcc -dynamiclib -o libhoge.dylib hoge.c
Java側の実装
Java側で以下のような実装をして、mainを実行すればOKです。
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JnaHoge {
public interface HogeInterface extends Library {
HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);
void hoge();
}
public static void main(String[] args) {
System.out.println("started");
HogeInterface.INSTANCE.hoge();
System.out.println("finished");
}
}
ディレクトリツリー
.
├── build.sbt
├── hoge.c
├── libhoge.dylib
├── src
├── main
│ ├── java
│ │ └── JnaHoge.java
│ ├── resources
│ └── scala
└── test
└── scala
実行結果
sbtの場合、sbt "runMain JnaHoge"
で実行できます。
作成したJnaHoge#main
を実行すると、
以下のどちらかのパターンで標準出力されるみたいです。
started
ほげぇ
finished
or
started
finished
ほげぇ
C言語で共有ライブラリを作って、Javaから呼び出すサンプルコード
下記リンクには、JNAでのC言語とJavaの型の対応が記載されています。
このリンクに書かれている型以外に、配列や構造体をJavaとCの間で受け渡せるようです。
引数なしでintの値を取得する
hoge.c
#include <stdio.h>
int getOne() {
return 1;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JnaHoge {
public interface HogeInterface extends Library {
HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);
int getOne();
}
public static void main(String[] args) {
System.out.println("started");
int one = HogeInterface.INSTANCE.getOne();
System.out.println(one);
System.out.println("finished");
}
}
JnaHoge#main
の実行結果:
started
1
finished
int型を渡してint型の値を得る
hoge.c
#include <stdio.h>
int squared(int x) {
return x * x;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JnaHoge {
public interface HogeInterface extends Library {
HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);
int squared(int x);
}
public static void main(String[] args) {
System.out.println("started");
int squared = HogeInterface.INSTANCE.squared(4);
System.out.println(squared);
System.out.println("finished");
}
}
実行結果:
started
16
finished
String型を渡してString型の値を得る
hoge.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* appendHoge(char* chars) {
char hoge[] = "hoge";
char* newChars = malloc(sizeof(chars) + sizeof(hoge));
memcpy(newChars, chars, sizeof(chars));
strcat(newChars, hoge);
return newChars;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JnaHoge {
public interface HogeInterface extends Library {
HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);
String appendHoge(String cs);
}
public static void main(String[] args) {
System.out.println("started");
String str = HogeInterface.INSTANCE.appendHoge("xxx");
System.out.println(str);
System.out.println("finished");
}
}
実行結果:
started
xxxhoge
finished
配列を渡して配列を得る
hoge.c
#include <stdio.h>
// 引数resultを戻り値として扱う
void hoge(int* nums, int* result) {
result[0] = nums[0] * 10;
result[1] = nums[1] * 10;
result[2] = nums[2] * 10;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JnaHoge {
public interface HogeInterface extends Library {
HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);
void hoge(int[] array, int[] newArray);
}
public static void main(String[] args) {
System.out.println("started");
int[] array = {4, 5, 6};
int[] newArray = new int[3];
HogeInterface.INSTANCE.hoge(array, newArray);
System.out.println(newArray[0]);
System.out.println(newArray[1]);
System.out.println(newArray[2]);
System.out.println("finished");
}
}
実行結果:
started
40
50
60
finished
構造体を渡してJavaのクラスを得る
hoge.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int age;
char* name;
} PERSON;
PERSON* setName(PERSON *p, char* name) {
p->name = name;
return p;
}
JnaHoge.java
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
public class JnaHoge {
public interface HogeInterface extends Library {
HogeInterface INSTANCE = Native.load("hoge", HogeInterface.class);
@Structure.FieldOrder({"age", "name"})
public class Person extends Structure {
public int age;
public String name;
}
Person setName(Person person, String name);
}
public static void main(String[] args) {
System.out.println("started");
HogeInterface.Person person = new HogeInterface.Person();
HogeInterface.Person newPerson = HogeInterface.INSTANCE.setName(person, "パターソン");
System.out.println(newPerson.name + "(" + newPerson.age + ")");
System.out.println("finished");
}
}
実行結果:
started
パターソン(0)
finished