Scala Native 0.5.7がリリースされた。
主要なアップデートはリリースノートに書かれているが、面白いと思ったので紹介する。
- Scala Nativeとは(おさらい)
- バイナリ互換性
- C++標準ライブラリへの依存が削減
- clasのvtableのレイアウトが最適化された
- Java標準ライブラリの実装
- SCALANATIVE_THREAD_STACK_SIZE が設定可能になった
- LinuxでPIE (Position Independent Executables) に対応した
Scala Nativeとは(おさらい)
Scala Nativeとは、ScalaプロジェクトをLLVMを利用してバイナリにビルドするプロジェクト、コンパイラプラグイン群の総称である。
Scala Nativeを使うことでScalaコードをそのままネイティブバイナリにできるし、静的バイナリを作ることも可能だ:
ScalaコードをLLVMでコンパイルする都合、Javaライブラリ(JVMバイトコードになっている)に依存しているとコンパイルできないので注意。
バイナリ互換性
Scala Native 0.5.7は0.5系の全てのバイナリに対して後方互換だ(つまり、呼び出すことができる)が、バイナリ前方互換性がない。つまりScala Native 0.5.6のプログラムから0.5.7でビルドされたライブラリを呼び出せない。 必要に応じてリビルドが必要である。(Scala Nativeはまだメジャーバージョンが1に到達していないためこういうbreaking changesは割とある)
C++標準ライブラリへの依存が削減
Unix環境でScala Nativeにビルドする場合、これまでC++標準ライブラリに依存していた(動的リンクしていた)のだが、0.5.7からは依存不要になった。
実際にscala-cliを用いて確認したところ、確かに依存性が減っていた。
このようなテストコードを用意する:
//> using scala 3.6.3 //> using platform native println("Hello, Scala Native!")
scala-cliを使ってバイナリにビルドする:
% scala-cli package -o "code056.out" --native-version=0.5.6 code.scala.sc % scala-cli package -o "code057.out" --native-version=0.5.7 code.scala.sc
lddを使うとバイナリが動的依存しているライブラリを確認できる:
% ldd code056.out
linux-vdso.so.1 (0x00007ffc14257000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3f34d75000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f3f34d6f000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3f34b8d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3f34a3e000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3f34a23000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3f34831000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3f34dac000)
% ldd code057.out
linux-vdso.so.1 (0x00007ffd3cd85000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffaab754000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ffaab74e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffaab55c000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffaab78b000)
libstdc++.soへの依存と、libm.soへの依存、libgcc_s.soへの依存が取れているのがわかる。
もともとScala Nativeは例外ハンドリングまわりでC++標準ライブラリに依存していたのだが、今回は例外ハンドリングに必要な最小限の処理を自前で実装したことにより依存が取れたとのこと。ただしLTO(Link Time Optimization)を有効化している場合とWindows環境でビルドした場合は引き続きC++標準ライブラリに依存する。これは未解決の問題が残っているため。
また嬉しい副作用としてStack Overflowエラーのハンドリングが改善し、これまではプログラムが終了するだけだったが検知してハンドルできるようになった。
ファイルサイズはちょっと太った。
% ls -lah Permissions Size User Date Modified Name drwxr-xr-x - windymelt 27 2月 00:29 .bsp/ drwxr-xr-x - windymelt 27 2月 00:29 .scala-build/ .rw-r--r-- 82 windymelt 27 2月 00:29 code.scala.sc .rwxr-xr-x 1.2M windymelt 27 2月 00:35 code056.out* .rwxr-xr-x 1.3M windymelt 27 2月 00:36 code057.out*
clasのvtableのレイアウトが最適化された
classをScala Native上で表現するためにvirtual tableを利用しているところ、これが改善されてバイナリサイズの削減が見込めるようだ。
The size of small binaries might slightly increase
とのことなので、数MiBレベルの元々小さいバイナリはやや大きくなり、数十MiBレベルの元々大きかったバイナリが恩恵を受けるようだ。もしかするとバイナリが太ったのはこれのせいかもしれない。
Java標準ライブラリの実装
JDK9以降に実装された標準ライブラリの数多くの処理がポートされた。
一例を挙げると、JDK11のString#linesが実装された:
SCALANATIVE_THREAD_STACK_SIZE が設定可能になった
環境変数 SCALANATIVE_THREAD_STACK_SIZE が設定可能になった。これはJVMの-Xssに対応し、スレッドのスタックサイズを設定できる。