S-JIS[2024-09-23] 変更履歴

Java外部関数およびメモリーAPI SymbolLookup

Java外部関数およびメモリーAPIのSymbolLookupのメモ。


概要

SymbolLookupは、シンボルのポインターを取得する為のインターフェース。

import java.lang.foreign.SymbolLookup;

SymbolLookupの取得方法

SymbolLookupのインスタンスを取得する方法は、どのライブラリーを対象とするか(どのライブラリーを読み込むか)で異なる。


System.loadLibrary()やSystem.load()を使う場合

System.load()で読み込んだライブラリーを対象とする場合は、loaderLookupを使う。

    System.load("C:/example/ffi/ffi-example-rust/target/release/ffi_example_rust.dll");

    SymbolLookup symbolLookup = SymbolLookup.loaderLookup();

System.load()にはライブラリーファイルのパスを指定する。


System.loadLibrary()で読み込んだライブラリーを対象とする場合も、loaderLookupを使う。

    System.loadLibrary("ffi_example_rust");

    SymbolLookup symbolLookup = SymbolLookup.loaderLookup();

System.loadLibrary()にはライブラリーファイルのファイル名(拡張子無し)を指定する。
ffi_example_rustを指定した場合、実際に読まれるファイルは、Windowsならffi_example_rust.dllになるし、Linuxならffi_example_rust.soになるはず。

System.loadLibrary()を使う場合は、実行時にライブラリーファイルの場所(ディレクトリー)を指定してやる必要がある。
javaコマンドの-Djava.library.pathオプションか、環境変数(Linuxの場合はLD_LIBRARY_PATH、Windowsの場合はPATH)でライブラリーファイルのディレクトリーを指定する。

> java -Djava.library.path=C:/example/ffi/ffi-example-rust/target/release com.example.ffi.FfiExample

OS標準ライブラリーを使いたい場合

OSの標準ライブラリーを使いたい場合は、LinkerのdefaultLookupを使う。

import java.lang.foreign.Linker;
    Linker linker = Linker.nativeLinker();
    SymbolLookup stdLib = linker.defaultLookup();

OSの特定ライブラリーを使いたい場合

OSの特定のライブラリーを使いたい場合は、libraryLookupでライブラリー名を指定する。

    SymbolLookup stdLib = SymbolLookup.libraryLookup("libc.so.6", arena);

ライブラリーファイルのパスを指定したい場合

libraryLookupでライブラリーファイルのパスを指定できる。

import java.nio.file.Path;
    var path = Path.of("C:/example/ffi/ffi-example-rust/target/release/ffi_example_rust.dll");
    var symbolLookup = SymbolLookup.libraryLookup(path, arena);

SymbolLookupのメソッド

メソッド 説明
Optional<MemorySegment> find(String name) シンボルを取得する。
見つからなかった場合はOptional.empty()が返る。
MemorySegment add = symbolLookup.find("add").orElseThrow();
MemorySegment findOrThrow(String name) シンボルを取得する。(Java23以降)
見つからなかった場合はNoSuchElementExceptionがスローされる。
MemorySegment add = symbolLookup.findOrThrow("add");
SymbolLookup or(SymbolLookup other) SymbolLookupのチェーン。 var lookup = SymbolLookup.libraryLookup("foo", arena)
.or(SymbolLookup.libraryLookup("bar", arena))
.or(SymbolLookup.loaderLookup());

find("add").orElseThrow()」の場合、シンボルが見つからなかったら「NoSuchElementException: No value present」がスローされることになる。(メッセージの中にシンボル名は出てこない)
findOrThrow("add")」であれば、「NoSuchElementException: Symbol not found: add」のようにシンボル名がメッセージの中に含まれているので分かりやすい。


外部関数およびメモリーAPIへ戻る / Java目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま