NetBSDで最新のMozcを使う 1

この記事は、NetBSD Advent Calendar 2023の19日目の記事です。

はじめに

私自身はSKKを常用しているので、連文節日本語かな漢字変換の世間の流れを良く知りませんが、 Google日本語入力のオープンソース版であるMozcが、NetBSDで利用できるなかで、 一番快適なのではないかと思っています。

ですが、最近のProtocol Bufferパッケージ(pkgsrc/deve/protobuf)のアップデートで、 pkgsrc/inputmethod以下にあるMozc関連のパッケージがビルドに失敗するようになって しまったようです。

ちょうどpkgsrcは4半期のフリーズの時期ですので、実際にはアップデートはできていませんが、 Mozcを最新のタグである2.29.5268.102というバージョンにアップデートする準備が だいたい整いましたので、アップデートのために実施したことを書いておきたいと思います。

最近のMozcのビルドの仕組み

最近のMozcは、Googleの提供しているBazelというビルド・オートメーション・システムを 利用するようになっています。 pkgsrcに現在含まれているMozc関連のパッケージは、GYPというビルド・オートメーション・ツール を使っていましたが、少なくともNetBSDで利用する際にベースとなるLinuxでのビルドには、 GYPはもう使えないようです。

と言うことで、Bazelのパッケージを先に作成する必要があります。

Bazelのパッケージを作る

Bazelをビルドするには、2つの方法があるようです。 Bazelを使ってBazelをビルドする方法と、Bazelを使わずBazelをビルドする方法です。 NetBSD用のBazelバイナリーは配布されていませんので、後者の方法(ブートストラップする方法)を使うしかありません。 ブートストラップする場合には、Javaの.jarファイルが実行でき、Python 3も使えれば良いようです。

Bazelのソースコードを確認する

NetBSDでBazelをブートストラップしようとすると、NetBSDという選択肢がないとjavaコマンドに 文句を言われてしまい、先に進めません。 ブートストラップ用の配布物に含まれる.jarファイルがNetBSDに対応していないために、 このようなエラーが発生しているようです。 Bazelファイル(WORKSPACE、BUILD、*.bzl)と.javaファイルをLinuxやOpenBSD、FreeBSDでgrepし、NetBSDも同様に 定義をしたり、条件節を追加したりしてやります。 具体的な内容は、pkgsrc/wip/bazel/patches以下を見ていただければと思います。 この時点で気付いた以上のものが含まれてはいますが…。

Bazelのブートストラップ・キットを作り直す

.jarファイルの生成自体は、うまくBazelファイルを編集し、pkgsrc/pkgtools/libkverを 使えばNetBSDでもビルドできましたが、Linux/x86_64環境でビルドしてしまうのが一番簡単です。 bazel-distfileターゲットを実行すれば、.zipアーカイブでブートストラップ・キットが できあがるはずと思うのですが、scripts/bootstrap以下のファイルが含まれていませんでした。 これも元のブートストラップ・キットからコピーして再度手動でアーカイブファイルを作成し直して、 これをNetBSD環境へ持って行きます。 LOCAL_PORTS/bazel-6.4.0-dist-netbsd.tar.gzから最終的なブートストラップ・キットは 入手できます。 これ以降、Bazelファイルの修正が不足していて修正する必要が出て来るのですが、Bazelファイル を直しても、Linuxでブートストラップ・キットを作り直す必要はありませんでした。 修正して再度アーカイブ・ファイルを作成するだけで大丈夫でした。

Bazelの隔離機能とpkgsrcの隔離機能が競合する

Bazelは、一貫性のあるビルドを実行するために、ビルド用のサンドボックスを提供しているようです。 pkgsrcも、buildlink3という仕組みで、サンドボックス的な環境を提供しています。 ですが、2つの機能は少し発想が異なるようで、両立させるのは私には無理でした。

この時点で認識できた競合した事項を記載しておきます。

  • C/C++コンパイラーやstripコマンド等が絶対パスで埋め込まれてしまいます。 これによって、pkgsrcのcwrqapperのccコマンドやc++コマンド等をビルド時に使用すると、 WRKSRC以下の絶対パスがBazelコマンドに埋め込まれてしまい、実質的に使えないバイナリーに なってしまいます。
  • できたbazelバイナリーを実行してみて、libjava.soが見付からないとエラーが出るため JAVA_HOMEの設定がおかしい、あるいはどこかで上書きされているのではないかと、 この時は考えていたのですが、これは勘違いでした。

Bazelのランタイムエラーを解析し、修正する

生成されたbazelコマンドを実行すると、

Error: could not find libjava.so
Error: Could not find Java SE Runtime Environment.

と表示されて、動きません。 検索すると、 Java error on AIX #6655 に同じ問題に悩んでいるAIXへ移植しようとしている人がいたのですが、 解決することなくissueはクローズされてしまっています。

何もヒントがウェブ上にはないようなので、lang/openjdk11でこのエラーメッセージを 出している箇所を検索してみることにしました。

すると、 jdk11u-jdk-11.0.21-9-1/src/java.base/unix/native/libjli/java_md_common.c の中の、以下の関数のdladdr()が想定されるlibjli.soのパスではなく、bazel()という文字列を 返しているのが良くないと分かりました。

jboolean
GetApplicationHomeFromDll(char *buf, jint bufsize)
{
    /* try to find ourselves instead */
    Dl_info info;
    if (dladdr((void*)&GetApplicationHomeFromDll, &info) != 0) {
        char *path = realpath(info.dli_fname, buf);
        if (path == buf) {
            return TruncatePath(buf);
        }
    }
    return JNI_FALSE;
}

lang/oprnjdk11では、libjliは静的にリンクされています。 それがいけなさそうです。

jdk11u-jdk-11.0.21-9-1/make/launcher/LauncherCommon.gmk を見ると、AIXとBSDの場合は、libjliを静的にリンクするようになっています。 さきほどのissueでAIXの人が同じように悩んでいたのも納得できました。 https://mail-index.netbsd.org/pkgsrc-changes/2023/12/09/msg288356.html のように変更し、lang/openjdk11でlibjli.soを動的にリンクするようにしました。 実際には、 https://mail-index.netbsd.org/pkgsrc-changes/2023/12/12/msg288501.html の適用も必要でした。

このopenjdk11を使えば、bazelコマンドは正常に動作しているように見えるくらいにはなりました。

時間の関係で、更にbazelを直しつつ、Mozcをビルドする話は次回に続きます。

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。

かりんとうの製造特許を探す

ALIC (独立行政法人 農畜産業振興機構)のウェブサイトには、いろいろおもしろい記事が掲載されているのだが、 そもそも、私はそれが検索で引っ掛かるような検索キーワードで検索することもないので、 自分で能動的に読みに行かないと、読む機会がなくなってしまう。 ...