Truffleを使って実装した言語をGraalVMで動かす方法、なかなか難しい。
まとめると、言語実装のクラスパスはtruffle.class.path.appendで追加して、言語利用側は普通のクラスパス、ということでした。
ということで、言語実装をlangに、起動プログラムをlauncherに置く感じにします。
sample ├lang │ └TruffleSample.java └launcher └Launcher.java
言語実装はこんな感じに。指定した文字列にhelloを付け加えるだけの言語です。
import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; import org.graalvm.polyglot.Context; @TruffleLanguage.Registration(name = "Minimum", id = "mini", defaultMimeType = TruffleSample.MIME, characterMimeTypes = TruffleSample.MIME) public class TruffleSample extends TruffleLanguage<Object>{ static final String MIME = "application/x-mini"; @Override protected CallTarget parse(ParsingRequest request) throws Exception { String text = request.getSource().getCharacters().toString(); return Truffle.getRuntime().createCallTarget(new RootNode(this){ @Override public Object execute(VirtualFrame frame) { return "Hello " + text; } }); } @Override protected Object createContext(Env env) { return new Object(); } @Override protected boolean isObjectOfLanguage(Object object) { return false; } }
こんな感じでコンパイル。$GHにGraalVMのパスが設定されてるとします。truffle-api.jarとtruffle-dsl-processor.jarをクラスパスに追加する必要があります。通常のJDKでコンパイルする場合にはgraal-sdk.jarも必要になりますが、GraalVMには含まれているので不要です。
sample$ cd lang lang$ $GH/bin/javac -cp $GH/jre/lib/truffle/truffle-api.jar:$GH/jre/lib/truffle/truffle-dsl-processor.jar TruffleSample.java
そうするとlanguageというファイルもできています。
lang$ cat language #Generated by com.oracle.truffle.dsl.processor.LanguageRegistrationProcessor #Fri Jan 04 15:43:28 GMT 2019 language1.characterMimeType.0=application/x-mini language1.className=TruffleSample language1.defaultMimeType=application/x-mini language1.id=mini language1.implementationName= language1.interactive=true language1.internal=false language1.name=Minimum language1.version=inherit
このファイルはMETA-INF/truffleに入ってる必要があります。mavenでjarを作ると適切なフォルダに作成されるのですが、javacでコンパイルするとそうならないので、自力で移動します。
lang$ mkdir META-INF lang$ mkdir META-INF/truffle lang$ mv language META-INF/truffle
起動用のプログラムはこんな感じ。
import org.graalvm.polyglot.Context; public class Launcher { public static void main(String... args) { Context ctx = Context.create("mini"); System.out.println(ctx.eval("mini", "test")); } }
org.graalvm.polyglotパッケージのあるgraal-sdk.jarはGraalVMに含まれてるので、クラスパスを追加する必要はありません。
lang$ cd ../launcher launcher$ $GH/bin/javac Launcher.java
そしたら上のフォルダに移動して実行。-Dtruffle.class.path.appendで言語のパス、-cpで起動プログラムのパスを指定しています。
launcher$ cd .. sample$ $GH/bin/java -Dtruffle.class.path.append=lang -cp launcher Launcher Hello test
動きました。