このエントリは2019年2月28日時点の以下の記事をベースにしています。
This entry is based on the following one as of February 28, 2019 (JST).
Using Panama “foreign” JDK
https://hg.openjdk.java.net/panama/dev/raw-file/c359a9e944de/doc/panama_foreign.html
Using Panama “foreign” JDK
panamaのforeignブランチのJDKを使うには2方法あります。
- panama リポジトリの”foreign”ブランチをローカルビルドする
http://hg.openjdk.java.net/panama/dev/ - 事前ビルド済みのpanama “foreign” 早期アクセスバイナリをダウンロードする
http://jdk.java.net/panama/
Javaで外部関数呼び出しを利用するには以下の3手順を踏みます。
- jextract を使ってCのヘッダーファイルに対するJavaインターフェースを生成する
- java.foreign APIを使ってCヘッダーインターフェースに対する実装を作成(バインド)する
- jextracted Javaインターフェースを使ってC関数を呼び出す
Windows notes
ほとんどのライブラリは間接的にVisual Studioランタイムライブラリに依存している(現時点ではjestractが問題なくヘッダーを抽出するにあたって必要)ため、Visual Studioのインストールが必要です。Windowsの例は Build Tools for Visual Studio 2017を用いてテストしました。
Build Tools for Visual Studio 2017
https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017
多くの大きなシステムヘッダーが推移的に含まれているため、jextractにたくさんの追加メモリを割り当てるべきで、そうすればjextractはかなり快適に実行できるでしょう。Windowsのサポートはごく最近になって追加されたため、jextractのメモリ使用量はまだ最適化されていない関係上、メモリをたくさん割り当てるのは回避策です。 追加引数として -J-Xmx8G
のように引数を渡せば、jextractにより多くのメモリを割り当てることができます。この例ではjextractに8GBのメモリを割り当てています。
コマンドはPowerShellでテストしています。
Embedding Python interpreter in your Java program (macOS)
jextract a Jar file for Python.h
jextract -l python2.7 \
-L /System/Library/Frameworks/Python.framework/Versions/2.7/lib --record-library-path \
--exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \
-t org.python \
/usr/include/python2.7/Python.h \
-o python.jar
Java program that uses extracted Python interface
// import java.foreign packages
import java.foreign.Libraries;
import java.foreign.Scope;
import java.foreign.memory.Pointer;
// import jextracted python 'header' classes
import static org.python.Python_h.*;
import static org.python.pythonrun_h.*;
public class PythonMain {
public static void main(String[] args) {
Py_Initialize();
try (Scope s = Scope.newNativeScope()) {
PyRun_SimpleStringFlags(s.allocateCString(
"print(sum([33, 55, 66])); print('Hello from Python!')n"),
Pointer.nullPointer());
}
Py_Finalize();
}
}
Running the Java code that calls Python interpreter
javac -cp python.jar PythonMain.java
java -cp python.jar:. PythonMain
jlinking Python Interpreter in your JDK (macOS)
Generating jmod using jextract
jextract -l python2.7 \
-L /System/Library/Frameworks/Python.framework/Versions/2.7/lib \
--exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \
-t org.python \
/usr/include/python2.7/Python.h \
-o org.python.jmod
Jlinking python module to create a JDK with Python in it
jdk.compiler と org.python モジュールを(jlinkで)生成したJDK(カスタムJRE)に追加します。
jlink --add-modules org.python,jdk.compiler --module-path . --output pythonjdk
Compile and run user code with “pythonjdk” jdk
環境変数 $PATH に $pythonjdk/bin
が含まれている前提で、以下のコマンドを実行しています。
javac PythonMain.java
java PythonMain
Embedding Python interpreter in your Java program (Ubuntu 16.04)
jextract a Jar file for Python.h
jextract -l python2.7 \
-L /usr/lib/python2.7/config-x86_64-linux-gnu --record-library-path \
--exclude-symbols .*_FromFormatV\|_.*\|PyOS_vsnprintf\|.*_VaParse.*\|.*_VaBuild.*\|PyBuffer_SizeFromFormat\|vasprintf\|vfprintf\|vprintf\|vsprintf \
-t org.python \
/usr/include/python2.7/Python.h \
-o python.jar
Compiling and Running Python Java example
macOSの章の手順に従ってください。
Embedding Python interpreter in your Java program (Windows)
jextract a Jar file for Python.h
ディレクトリ C:Python27
に python 2.7 がインストールされているものとします。
jextract -L "C:WindowsSystem32" -l python27 -o python.jar -t "org.python" --record-library-path C:Python27includePython.h
Compiling and Running Python Java example
javac -cp python.jar PythonMain.java
java -cp "python.jar;." PythonMain
Using sqlite3 library in your Java program (macOS)
jextract a jar file for sqlite3.h
jextract /usr/include/sqlite3.h -t org.sqlite -lsqlite3 \
-L /usr/lib --record-library-path \
--exclude-symbols sqlite3_vmprintf \
--exclude-symbols sqlite3_vsnprintf \
-o sqlite3.jar
Java sample that uses sqlite3 library
import java.lang.invoke.*;
import java.foreign.*;
import java.foreign.memory.*;
import org.sqlite.sqlite3.*;
import static org.sqlite.sqlite3_h.*;
public class SqliteMain {
public static void main(String[] args) throws Exception {
try ( Scope scope = Scope.newNativeScope()) {
// char* errMsg;
Pointer<Pointer<Byte>> errMsg = scope.allocate(NativeTypes.INT8.pointer());
// sqlite3* db;
Pointer<Pointer<sqlite3>> db = scope.allocate(LayoutType.ofStruct(sqlite3.class).pointer());
int rc = sqlite3_open(scope.allocateCString("employee.db"), db);
if (rc != 0) {
System.err.println("sqlite3_open failed: " + rc);return;
}
// create a new table
Pointer<Byte> sql = scope.allocateCString(
"CREATE TABLE EMPLOYEE (" +
" ID INT PRIMARY KEY NOT NULL," +
" NAME TEXT NOT NULL," +
" SALARY REAL NOT NULL )" );
// dummy ignoring callback
Callback<FI1> callback = scope.allocateCallback(FI1.class, (a,b,c,d)->0);
rc = sqlite3_exec(db.get(), sql, callback, Pointer.nullPointer(), errMsg);
if (rc != 0) {
System.err.println("sqlite3_exec failed: " + rc);
System.err.println("SQL error: " + Pointer.toString(errMsg.get()));
sqlite3_free(errMsg.get());
}
// insert two rows
sql = scope.allocateCString(
"INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
"VALUES (134, 'Xyz', 200000.0); " +
"INSERT INTO EMPLOYEE (ID,NAME,SALARY) " +
"VALUES (333, 'Abc', 100000.0);"
);
rc = sqlite3_exec(db.get(), sql, callback, Pointer.nullPointer(), errMsg);
if (rc != 0) {
System.err.println("sqlite3_exec failed: " + rc);
System.err.println("SQL error: " + Pointer.toString(errMsg.get()));
sqlite3_free(errMsg.get());
}
int[] rowNum = new int[1];
// callback to print rows from SELECT query
callback = scope.allocateCallback(FI1.class, (a, argc, argv, columnNames) -> {
System.out.println("Row num: " + rowNum[0]++);
System.out.println("numColumns = " + argc);
for (int i = 0; i < argc; i++) {
String name = Pointer.toString(columnNames.offset(i).get());
String value = Pointer.toString(argv.offset(i).get());
System.out.printf("%s = %sn", name, value);
}
return 0;
});
// select query
sql = scope.allocateCString("SELECT * FROM EMPLOYEE");
rc = sqlite3_exec(db.get(), sql, callback, Pointer.nullPointer(), errMsg);
if (rc != 0) {
System.err.println("sqlite3_exec failed: " + rc);
System.err.println("SQL error: " + Pointer.toString(errMsg.get()));
sqlite3_free(errMsg.get());
}
sqlite3_close(db.get());
}
}
}
Compiling and Running sqlite Java example
javac -cp sqlite3.jar SqlMain.java
java -cp sqlite3.jar:. SqlMain
Using sqlite3 library in your Java program (Ubuntu 16.04)
Installing sqlite3
Ubuntu (16.04) にsqlite3ヘッダーファイルとライブラリをインストールするには、以下のコマンドを実行する必要があります。
sudo apt-get install libsqlite3-dev
これを実行すると、sqlite3のヘッダーファイル(インストール先は /usr/include
)と共有ライブラリ(インストール先は /usr/lib/x86_64-linux-gnu
)をインストールします。
jextract a jar file for sqlite3.h
以下のコマンドを実行して sqliteを抽出します。
jextract /usr/include/sqlite3.h -t org.sqlite -lsqlite3 \
-L /usr/lib/x86_64-linux-gnu --record-library-path \
--exclude-symbols sqlite3_vmprintf \
--exclude-symbols sqlite3_vsnprintf \
-o sqlite3.jar
Compiling and Running sqlite Java example
macOS の手順を参照してください。上記の手順でライブラリを抽出すれば、サンプルプログラムがUbuntuでも動作するはずです。
Using BLAS library
BLAS とは高速な行列およびベクトル計算を可能にする有名なライブラリです。
BLAS (Basic Linear Algebra Subprograms)
http://www.netlib.org/blas/
Installing OpenBLAS (macOS)
Macの場合、BLASはOpenBLASライブラリの一部として利用できます。
OpenBLAS Wiki
https://github.com/xianyi/OpenBLAS/wiki
OpenBLASはGotoBLAS2の1.13 BSD版をベースにした最適化されたBLASライブラリです。
GotoBLAS2
https://www.tacc.utexas.edu/research-development/tacc-software/gotoblas2
openblasはHomeBrewを使ってインストールできます。
brew install openblas
/usr/local/opt/openblas
配下の include
と lib
ディレクトリにインストールされます。
Installing OpenBLAS (Ubuntu 16.04)
Ubuntuでは、BLASはatlasライブラリの一部として配布されます。 apt
を使ってatlasをインストールできます。
Automatically Tuned Linear Algebra Software (ATLAS)
http://math-atlas.sourceforge.net/
sudo apt-get install libatlas-base-dev
このコマンドはincludeファイルを/usr/include/atlas
にインストールするとともに、includeファイルに対応するライブラリを/usr/lib/atlas-dev
にインストールします。
jextracting cblas.h (macOS)
以下のコマンドを使ってmacOS上でcblas.hを抽出できます。
jextract -C "-D FORCE_OPENBLAS_COMPLEX_STRUCT" \
-L /usr/local/opt/openblas/lib -I /usr/local/opt/openblas \
-l openblas -t blas --record-library-path /usr/local/opt/openblas/include/cblas.h \
-o cblas.jar
FORCE_OPENBLAS_COMPLEX_STRUCT というdefineが必要なのは、jextractがまだC99 の_Complex
型に対応していないためです。その他のオプションは標準的なものです。
jextracting cblas.h (Ubuntu 16.04)
以下のコマンドを使ってUbuntuでcblas.hを抽出できます。
jextract -L /usr/lib/atlas-base -I /usr/include/atlas/ \
-l cblas -t blas --record-library-path \
/usr/include/atlas/cblas.h -o cblas.jar
Java sample code that uses cblas library
import blas.cblas;
import static blas.cblas_h.*;
import java.foreign.NativeTypes;
import java.foreign.Scope;
import java.foreign.memory.Array;
public class TestBlas {
public static void main(String[] args) {
@cblas.CBLAS_ORDER int Layout;
@cblas.CBLAS_TRANSPOSE int transa;
double alpha, beta;
int m, n, lda, incx, incy, i;
Layout = CblasColMajor;
transa = CblasNoTrans;
m = 4; /* Size of Column ( the number of rows ) */
n = 4; /* Size of Row ( the number of columns ) */
lda = 4; /* Leading dimension of 5 * 4 matrix is 5 */
incx = 1;
incy = 1;
alpha = 1;
beta = 0;
try (Scope sc = Scope.newNativeScope()){
Array<Double> a = sc.allocateArray(NativeTypes.DOUBLE, m * n);
Array<Double> x = sc.allocateArray(NativeTypes.DOUBLE, n);
Array<Double> y = sc.allocateArray(NativeTypes.DOUBLE, n);
/* The elements of the first column */
a.set(0, 1.0);
a.set(1, 2.0);
a.set(2, 3.0);
a.set(3, 4.0);
/* The elements of the second column */
a.set(m, 1.0);
a.set(m + 1, 1.0);
a.set(m + 2, 1.0);
a.set(m + 3, 1.0);
/* The elements of the third column */
a.set(m * 2, 3.0);
a.set(m * 2 + 1, 4.0);
a.set(m * 2 + 2, 5.0);
a.set(m * 2 + 3, 6.0);
/* The elements of the fourth column */
a.set(m * 3, 5.0);
a.set(m * 3 + 1, 6.0);
a.set(m * 3 + 2, 7.0);
a.set(m * 3 + 3, 8.0);
/* The elemetns of x and y */
x.set(0, 1.0);
x.set(1, 2.0);
x.set(2, 1.0);
x.set(3, 1.0);
y.set(0, 0.0);
y.set(1, 0.0);
y.set(2, 0.0);
y.set(3, 0.0);
cblas_dgemv(Layout, transa, m, n, alpha, a.elementPointer(), lda, x.elementPointer(), incx, beta,
y.elementPointer(), incy);
/* Print y */
for (i = 0; i < n; i++)
System.out.print(String.format(" y%d = %f\n", i, y.get(i)));
}
}
}
Compiling and running the above cblas samples
javac -cp cblas.jar TestBlas.java
java -cp cblas.jar:. TestBlas
Using LAPACK library (Ubuntu)
Ubuntuでは、(atlasを使って) blasをインストールするために使った同じ手順で、blas上でビルドされた線形代数計算ライブラリのLAPACKのライブラリのヘッダーファイルとライブラリをインストールします。
jextracting clapack.h (Ubuntu 16.04)
以下のコマンドを使ってLAPACKのヘッダーを抽出できます。
jextract -L /usr/lib/atlas-base/atlas -I /usr/include/atlas/ \
-l lapack -t lapack --record-library-path /usr/include/atlas/clapack.h -o clapack.jar
Java sample code that uses LAPACK library
import java.foreign.NativeTypes;
import java.foreign.Scope;
import java.foreign.memory.Array;
import static lapack.clapack_h.*;
import static lapack.cblas_h.*;
public class TestLapack {
public static void main(String[] args) {
/* Locals */
try (Scope sc = Scope.newNativeScope()) {
Array<Double> A = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
});
Array<Double> b = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
-10, 12, 14, 16, 18, -3, 14, 12, 16, 16
});
int info, m, n, lda, ldb, nrhs;
/* Initialization */
m = 5;
n = 3;
nrhs = 2;
lda = 5;
ldb = 5;
/* Print Entry Matrix */
print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
/* Print Right Rand Side */
print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
System.out.println();
/* Executable statements */
// printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
/* Solve least squares problem*/
info = clapack_dgels(CblasColMajor, CblasNoTrans, m, n, nrhs, A.elementPointer(), lda, b.elementPointer(), ldb);
/* Print Solution */
print_matrix_colmajor("Solution", n, nrhs, b, ldb );
System.out.println();
System.exit(info);
}
}
static void print_matrix_colmajor(String msg, int m, int n, Array<Double> mat, int ldm) {
int i, j;
System.out.printf("\n %s\n", msg);
for( i = 0; i < m; i++ ) {
for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.get(i+j*ldm));
System.out.printf( "\n" );
}
}
}
Compiling and running the above LAPACK sample
javac -cp clapack.jar TestLapack.java
java -cp clapack.jar:. TestLapack
Using LAPACK library (macOS)
macOSでは、lapackは /usr/opt/lapack
にインストールされます。
jextracting lapacke.h
jextract -L /usr/local/opt/lapack/lib -I /usr/local/opt/lapack/ \
-l lapacke -t lapack --record-library-path /usr/local/opt/lapack/include/lapacke.h -o clapack.jar
Java sample code that uses LAPACK library
import java.foreign.NativeTypes;
import java.foreign.Scope;
import java.foreign.memory.Array;
import static lapack.lapacke_h.*;
public class TestLapack {
public static void main(String[] args) {
/* Locals */
try (Scope sc = Scope.newNativeScope()) {
Array<Double> A = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
1, 2, 3, 4, 5, 1, 3, 5, 2, 4, 1, 4, 2, 5, 3
});
Array<Double> b = sc.allocateArray(NativeTypes.DOUBLE, new double[]{
-10, 12, 14, 16, 18, -3, 14, 12, 16, 16
});
int info, m, n, lda, ldb, nrhs;
/* Initialization */
m = 5;
n = 3;
nrhs = 2;
lda = 5;
ldb = 5;
/* Print Entry Matrix */
print_matrix_colmajor("Entry Matrix A", m, n, A, lda );
/* Print Right Rand Side */
print_matrix_colmajor("Right Hand Side b", n, nrhs, b, ldb );
System.out.println();
/* Executable statements */
// printf( "LAPACKE_dgels (col-major, high-level) Example Program Results\n" );
/* Solve least squares problem*/
info = LAPACKE_dgels(LAPACK_COL_MAJOR, (byte)'N', m, n, nrhs, A.elementPointer(), lda, b.elementPointer(), ldb);
/* Print Solution */
print_matrix_colmajor("Solution", n, nrhs, b, ldb );
System.out.println();
System.exit(info);
}
}
static void print_matrix_colmajor(String msg, int m, int n, Array<Double> mat, int ldm) {
int i, j;
System.out.printf("\n %s\n", msg);
for( i = 0; i < m; i++ ) {
for( j = 0; j < n; j++ ) System.out.printf(" %6.2f", mat.get(i+j*ldm));
System.out.printf( "\n" );
}
}
}
Compiling and running the above LAPACK sample
javac -cp clapack.jar TestLapack.java
java -cp clapack.jar:. TestLapack
Using libproc library to list processes from Java (macOS)
jextract a jar file for libproc.h
jextract -t org.unix -lproc -L /usr/lib — record-library-path -o libproc.jar /usr/include/libproc.h
Java program that uses libproc to list processes
import java.foreign.*;
import java.foreign.memory.*;
import static org.unix.libproc_h.*;
public class LibprocMain {
private static final int NAME_BUF_MAX = 256;
public static void main(String[] args) {
// Scope for native allocations
try (Scope s = Scope.newNativeScope()) {
// get the number of processes
int numPids = proc_listallpids(Pointer.nullPointer(), 0);
// allocate an array
Array<Integer> pids = s.allocateArray(NativeTypes.INT32, numPids);
// list all the pids into the native array
proc_listallpids(pids.elementPointer(), numPids);
// convert native array to java array
int[] jpids = pids.toArray(num -> new int[num]);
// buffer for process name
Pointer<Byte> nameBuf = s.allocate(NativeTypes.INT8, NAME_BUF_MAX);
for (int i = 0; i < jpids.length; i++) {
int pid = jpids[i];
// get the process name
proc_name(pid, nameBuf, NAME_BUF_MAX);
String procName = Pointer.toString(nameBuf);
// print pid and process name
System.out.printf("%d %s\n", pid, procName);
}
}
}
}
Running the Java code that uses libproc
javac -cp libproc.jar LibprocMain.java
java -cp libproc.jar:. LibprocMain
Using readline library from Java code (macOS)
jextract a jar file for readline.h
jextract -l readline -L /usr/local/opt/readline/lib/ --record-library-path \
-t org.unix \
/usr/include/readline/readline.h \
--exclude-symbol readline_echoing_p -o readline.jar
Java code that uses readline
import java.foreign.*;
import java.foreign.memory.*;
import static org.unix.readline_h.*;
public class Readline {
public static void main(String[] args) {
// Scope for native allocations
try (Scope s = Scope.newNativeScope()) {
// allocate C memory initialized with Java string content
var pstr = s.allocateCString("name? ");
// call "readline" API
var p = readline(pstr);
// print char* as is
System.out.println(p);
// convert char* ptr from readline as Java String & print it
System.out.println(Pointer.toString(p));
}
}
}
Running the java code that uses readline
javac -cp readline.jar Readline.java
java -cp readline.jar:. Readline
Using libcurl from Java (macOS)
jextract a jar for curl.h
jextract -t org.unix -L /usr/lib -lcurl --record-library-path /usr/include/curl/curl.h -o curl.jar
Java code that uses libcurl
import java.lang.invoke.*;
import java.foreign.*;
import java.foreign.memory.*;
import org.unix.curl.*;
import static org.unix.curl_h.*;
import static org.unix.easy_h.*;
public class CurlMain {
public static void main(String[] args) {
try (Scope s = Scope.newNativeScope()) {
curl_global_init(CURL_GLOBAL_DEFAULT);
Pointer<Void> curl = curl_easy_init();
if(!curl.isNull()) {
Pointer<Byte> url = s.allocateCString(args[0]);
curl_easy_setopt(curl, CURLOPT_URL, url);
int res = curl_easy_perform(curl);
if (res != CURLE_OK) {
curl_easy_cleanup(curl);
}
}
curl_global_cleanup();
}
}
}
Running the java code that uses libcurl
javac -cp curl.jar CurlMain.java
java -cp curl.jar:. CurlMain <url>
Using unistd.h from Java code (Linux)
jextract a jar file for unistd.h
jextract /usr/include/unistd.h -t org.unix -o unistd.jar
Java code that calls getpid
import java.foreign.*;
import java.lang.invoke.*;
import org.unix.unistd;
public class Getpid {
public static void main(String[] args) {
// bind unistd interface
var u = Libraries.bind(MethodHandles.lookup(), unistd.class);
// call getpid from the unistd.h
System.out.println(u.getpid());
// check process id from Java API!
System.out.println(ProcessHandle.current().pid());
}
}
Running the Java code that uses getpid
javac -cp unistd.jar Getpid.java
java -cp unistd.jar:. Getpid
Using OpenGL graphic library (Ubuntu 16.04)
OpenGL は人気のある可搬性のあるグラフィックライブラリです。
OpenGL — The Industry Standard for High Performance Graphics
https://www.opengl.org/
Installing OpenGL (Ubuntu 16.04)
関連するOpenGLのヘッダーファイルとライブラリのインストールは、どのグラフィックカードが対象となるプラットフォームにインストールされているかに依存するため、少しトリッキーになることがあります。動作するようにするための変更はそれほど多くないのですが、以下の説明では、(NvidiaまたはAMDの)プロプライエタリなものではなく、(mesaなどの)OpenGLの標準バージョンを使用していることを前提としています。
OpenGLは常に多くの他のライブラリ、具体的にはGLUやglutと結びついています。以下のようにこれらのライブラリはすべて apt
を使ってインストールできます。
sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev
インストールが成功すると、OpenGLのヘッダーファイルは/usr/include/GL
に、ライブラリは/usr/lib/x86_64-linux-gnu/
にそれぞれ配置されていることがわかります。
jextracting OpenGL (Ubuntu 16.04)
OpenGLライブラリの抽出にあたっては、以下のコマンドで十分です。
jextract -L /usr/lib/x86_64-linux-gnu -l glut -l GLU -l GL --record-library-path -t opengl -o opengl.jar /usr/include/GL/glut.h
glutは別のライブラリ (GLU とGL) に依存しているため、jextractに追加のヘッダーを指定する必要はありません。
Java sample code that uses the OpenGL library
import java.foreign.NativeTypes;
import java.foreign.Scope;
import java.foreign.memory.Array;
import java.foreign.memory.Pointer;
import static opengl.gl_h.*;
import static opengl.freeglut_std_h.*;
public class Teapot {
float rot = 0;
Teapot(Scope sc) {
// Misc Parameters
Array<Float> pos = sc.allocateArray(NativeTypes.FLOAT, new float[] {0.0f, 15.0f, -15.0f, 0});
Array<Float> spec = sc.allocateArray(NativeTypes.FLOAT, new float[] {1, 1, 1, 0});
Array<Float> shini = sc.allocateArray(NativeTypes.FLOAT, new float[] {113});
// Reset Background
glClearColor(0, 0, 0, 0);
// Setup Lighting
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0, GL_POSITION, pos.elementPointer());
glLightfv(GL_LIGHT0, GL_AMBIENT, spec.elementPointer());
glLightfv(GL_LIGHT0, GL_DIFFUSE, spec.elementPointer());
glLightfv(GL_LIGHT0, GL_SPECULAR, spec.elementPointer());
glMaterialfv(GL_FRONT, GL_SHININESS, shini.elementPointer());
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(-20, 1, 1, 0);
glRotatef(rot, 0, 1, 0);
glutSolidTeapot(0.5);
glPopMatrix();
glutSwapBuffers();
}
void onIdle() {
rot += 0.1;
glutPostRedisplay();
}
public static void main(String[] args) {
try (Scope sc = Scope.newNativeScope()) {
Pointer<Integer> argc = sc.allocate(NativeTypes.INT32);
argc.set(0);
glutInit(argc, Pointer.nullPointer());
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(900, 900);
glutCreateWindow(sc.allocateCString("Hello Panama!"));
Teapot teapot = new Teapot(sc);
glutDisplayFunc(sc.allocateCallback(teapot::display));
glutIdleFunc(sc.allocateCallback(teapot::onIdle));
glutMainLoop();
}
}
}
Running the Java code that uses OpenGL (Ubuntu 16.04)
javac -cp opengl.jar Teapot.java
java -cp opengl.jar:. Teapot
Using OpenGL graphic library (Windows)
Installing OpenGL
以下の場所からMSVC用のfreeglutパッケージをダウンロードします。
freeglut Windows Development Libraries
https://www.transmissionzero.co.uk/software/freeglut-devel/
freeglutのZipファイルを展開します。
jextracting OpenGL
展開したZipファイルのルートディレクトリに移動して、以下のコマンドを実行します。
$inc = "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0"
jextract -L C:\Windows\System32\ -L .\freeglut\bin\x64\ -l opengl32 -l freeglut -t opengl -o opengl.jar -m "$inc\um\gl=opengl" --record-library-path .\freeglut\include\GL\glut.h
$inc
に割り当てたディレクトリはあくまでもサンプルであり、システムに依存します。Pathの最後のビルド番号 (この例では10.0.17134.0
) が、親フォルダに現れているバージョン (この例ではC:Program Files (x86)Windows Kits10Include
なので 10
) の最新版であることを確認してください。
多数の警告が出ますが、jarファイルが作業ディレクトリに生成されていれば、展開は成功しています。
Java sample code that uses the OpenGL library
これはUbuntuの章に記載したものと同じです。
Running the Java code that uses OpenGL
javac -cp .opengl.jar Teapot.java
java -cp "opengl.jar;." Teapot
Using TensorFlow C API (macOS)
“TensorFlow provides a C API that can be used to build bindings for other languages. The API is defined in c_api.h and designed for simplicity and uniformity rather than convenience.” (TensorFlowはC言語のAPIを提供しており、これを使って多言語のバインディングを作成できます。APIはc_api.hで定義され、利便性よりはむしろ簡潔性と統一性のために設計されています。)
Install TensorFlow for C
https://www.tensorflow.org/install/lang_c
Installing libtensorflow
上記URLに記載のセットアップ手順に従ってください。Macの場合、HomeBrewを使ってもibtensorflowをインストールできます。
brew install libtensorflow
Tensorflowはlibtensorflowを.soという拡張子の形(共有ライブラリ)で同梱しています。JavaはmacOSの場合、.dylibという拡張子を想定しているためうまく動作しません。これを回避するために、シンボリックリンクを作成します。
sudo ln -s /usr/local/lib/libtensorflow.so /usr/local/lib/libtensorflow.dylib
jextracting libtensorflow c_api.h
以下のコマンドを使ってc_api.hを抽出できます。
jextract -C -x -C c++ \
-L /usr/local/lib -l tensorflow --record-library-path \
-o tf.jar -t org.tensorflow.panama \
/usr/local/include/tensorflow/c/c_api.h
TensorFlow C APIを抽出する際の注意点は、C++スタイルで引数なしで関数プロトタイプを宣言することです。例えば、 TF_Vision()
は TF_Version(void)
のようにCスタイルではなく、不完全なC関数プロトタイプと見なされます。不完全な関数プロトタイプは可変長引数関数になるでしょう。それを避けるために、-C -x -C c++
を使って、clangの -x c++
オプションをjextractに渡す必要があります。
Java sample code that uses tensorflow library
import java.foreign.NativeTypes;
import java.foreign.Scope;
import java.foreign.memory.Array;
import java.foreign.memory.LayoutType;
import java.foreign.memory.Pointer;
import org.tensorflow.panama.c_api.TF_DataType;
import org.tensorflow.panama.c_api.TF_Graph;
import org.tensorflow.panama.c_api.TF_Operation;
import org.tensorflow.panama.c_api.TF_OperationDescription;
import org.tensorflow.panama.c_api.TF_Output;
import org.tensorflow.panama.c_api.TF_Session;
import org.tensorflow.panama.c_api.TF_SessionOptions;
import org.tensorflow.panama.c_api.TF_Status;
import org.tensorflow.panama.c_api.TF_Tensor;
import static org.tensorflow.panama.c_api_h.*;
public class TensorFlowExample {
static Pointer<TF_Operation> PlaceHolder(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
@TF_DataType int dtype, String name) {
try (var s = Scope.newNativeScope()) {
Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
s.allocateCString("Placeholder"), s.allocateCString(name));
TF_SetAttrType(desc, s.allocateCString("dtype"), TF_FLOAT);
return TF_FinishOperation(desc, status);
}
}
static Pointer<TF_Operation> ConstValue(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
Pointer<TF_Tensor> tensor, String name) {
try (var s = Scope.newNativeScope()) {
Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
s.allocateCString("Const"), s.allocateCString(name));
TF_SetAttrTensor(desc, s.allocateCString("value"), tensor, status);
TF_SetAttrType(desc, s.allocateCString("dtype"), TF_TensorType(tensor));
return TF_FinishOperation(desc, status);
}
}
static Pointer<TF_Operation> Add(Pointer<TF_Graph> graph, Pointer<TF_Status> status,
Pointer<TF_Operation> one, Pointer<TF_Operation> two,
String name) {
try (var s = Scope.newNativeScope()) {
Pointer<TF_OperationDescription> desc = TF_NewOperation(graph,
s.allocateCString("AddN"), s.allocateCString(name));
Array<TF_Output> add_inputs = s.allocateArray(
LayoutType.ofStruct(TF_Output.class),2);
add_inputs.get(0).oper$set(one);
add_inputs.get(0).index$set(0);
add_inputs.get(1).oper$set(two);
add_inputs.get(1).index$set(0);
TF_AddInputList(desc, add_inputs.elementPointer(), 2);
return TF_FinishOperation(desc, status);
}
}
public static void main(String... args) {
System.out.println("TensorFlow C library version: " + Pointer.toString(TF_Version()));
Pointer<TF_Graph> graph = TF_NewGraph();
Pointer<TF_SessionOptions> options = TF_NewSessionOptions();
Pointer<TF_Status> status = TF_NewStatus();
Pointer<TF_Session> session = TF_NewSession(graph, options, status);
float in_val_one = 4.0f;
float const_two = 2.0f;
Pointer<TF_Tensor> tensor_in = TF_AllocateTensor(TF_FLOAT, Pointer.nullPointer(), 0, Float.BYTES);
TF_TensorData(tensor_in).cast(NativeTypes.FLOAT).set(in_val_one);
Pointer<TF_Tensor> tensor_const_two = TF_AllocateTensor(TF_FLOAT, Pointer.nullPointer(), 0, Float.BYTES);
TF_TensorData(tensor_const_two).cast(NativeTypes.FLOAT).set(const_two);
// Operations
Pointer<TF_Operation> feed = PlaceHolder(graph, status, TF_FLOAT, "feed");
Pointer<TF_Operation> two = ConstValue(graph, status, tensor_const_two, "const");
Pointer<TF_Operation> add = Add(graph, status, feed, two, "add");
try (var s = Scope.newNativeScope()) {
var ltPtrTensor = LayoutType.ofStruct(TF_Tensor.class).pointer();
// Session Inputs
TF_Output input_operations = s.allocateStruct(TF_Output.class);
input_operations.oper$set(feed);
input_operations.index$set(0);
Pointer<Pointer<TF_Tensor>> input_tensors = s.allocate(ltPtrTensor);
input_tensors.set(tensor_in);
// Session Outputs
TF_Output output_operations = s.allocateStruct(TF_Output.class);
output_operations.oper$set(add);
output_operations.index$set(0);
Pointer<Pointer<TF_Tensor>> output_tensors = s.allocate(ltPtrTensor);
TF_SessionRun(session, Pointer.nullPointer(),
// Inputs
input_operations.ptr(), input_tensors, 1,
// Outputs
output_operations.ptr(), output_tensors, 1,
// Target operations
Pointer.nullPointer(), 0, Pointer.nullPointer(),
status);
System.out.println(String.format("Session Run Status: %d - %s",
TF_GetCode(status), Pointer.toString(TF_Message(status))));
Pointer<TF_Tensor> tensor_out = output_tensors.get();
System.out.println("Output Tensor Type: " + TF_TensorType(tensor_out));
float outval = TF_TensorData(tensor_out).cast(NativeTypes.FLOAT).get();
System.out.println("Output Tensor Value: " + outval);
TF_CloseSession(session, status);
TF_DeleteSession(session, status);
TF_DeleteSessionOptions(options);
TF_DeleteGraph(graph);
TF_DeleteTensor(tensor_in);
TF_DeleteTensor(tensor_out);
TF_DeleteTensor(tensor_const_two);
TF_DeleteStatus(status);
}
}
}
Compiling and running the above TensorFlow sample
javac -cp tf.jar TensorFlowExample.java
java -cp tf.jar:. TensorFlowExample
Using TensorFlow C API (Windows)
Installing libtensorflow
以下のURLからバイナリをダウンロードできます。ダウンロードしたらZipファイルを展開してください。
Install TensorFlow for C
https://www.tensorflow.org/install/lang_c
jextracting libtensorflow c_api.h
不正な関数プロトタイプに関するmacOSの命令で概説された問題はまだ存在します(TensorFlowのGitHubリポジトリで解決されましたが、この変更はバイナリディストリビューションには反映されていません)。しかしながら、Windowsではこれを回避するjextractコマンドがないため、 includecc_api.hを正しく抽出するには、誤った関数プロトタイプを手作業で修正するしかありません。
TF_Version() -> TF_Version(void)
TF_NewGraph() -> TF_NewGraph(void)
TF_NewSessionOptions() -> TF_NewSessionOptions(void)
TF_NewStatus() -> TF_NewStatus(void)
TF_NewBuffer() -> TF_NewBuffer(void)
TF_NewImportGraphDefOptions() -> TF_NewImportGraphDefOptions(void)
TF_GetAllOpList() -> TF_GetAllOpList(void)
修正が完了したら、libtensorflowのルートディレクトリから以下のjextractコマンドを使うことができます。
jextract -L .\lib -l tensorflow -o tf.jar -t "org.tensorflow.panama" --record-library-path .\include\tensorflow\c\c_api.h
Java sample code that uses tensorflow library
macOSの章と同じです。
Compiling and running the above TensorFlow sample
javac -cp tf.jar TensorFlowExample.java
java -cp "tf.jar;." TensorFlowExample