GHCのJavaScript backendを使ってみる
参考にしたページ
ghc-9.10.1-src.tar.xzをダウンロード。
% tar Jxvf ghc-9.10.1-src.tar.xz
% cd ghc-9.10.1
% ./boot.source
% emconfigure ./configure --target=javascript-unknown-ghcjs GHC=/home/.../.stack/.../bin/ghc
% stack install alex
% ./hadrian/build -j12 --flavour=guick --bignum=native --docs=none
% _build/stage1/bin/javascript-unknown-ghcjs-ghc --info | grep Target
% cd ..
% mkdir src
% vi src/hello.hs
% ghc-9.10.1/_build/stage1/bin/javascript-unknown-ghcjs-ghc src/hello.hs
% ./src/hello
% firefox src/hello.jsexe/index.html
あと、buildの前にemscriptenのインストールが必要。
パスを通すのに~/.zshrcに以下を追記
export EMSDK_QUIET=1
source "/home/foobar/hogepiyo/emsdk/emsdk_env.hs"
実行可能ファイルはghc-9.10.1/_build/bin/javascript-ghcjs-ghcとなっている。が、これだけを/usr/local/binにコピーしても実行できない。_build/stage1/lib以下の、settings, package.conf.d/, ghc-usage.txt, javascript-ghc-js-ghc-9.10.1/もコピーする必要がある。make installとか、そういうやりかたもあるのだと思うのだけど、見つけられなかった。
どうやら
% ./hadrian/build install
みたいにできるようだ。
% ./hadrian/build install --prefix=/usr/local/ --docs=none
としたのだけど、コンパイルからまた始まってしまった。--prefixを変えたからか。
もしかすると、--bignum=nativeが必要なのかもしれない。
Stackにあまえていたけど、JavaScriptバックエンドを使うにはGHCの素のパッケージ管理を学ぶ必要があるかもしれない。
./hadrian/build installはうまくいかないな。
sudoでglobalにinstallしようとしていたのが良くなかった。GHCupでローカルにインストールされてたghcやcabalが見つからなかったという話だ。~/.local/以下にインストールすれば大丈夫かもしれない。
command line: sh configure --prefix=/home/foo/.local/
===> Command failed with error code: 1
checking emsdk version... Command failed
となるな。
このへんの話がJavaScriptバックエンドにおけるパッケージの話に関連してそう。
GHCはHaskellからJavaScriptに変換するときに一度llvmにするのかな。
しばらくはpackageは使わずにall-in-oneでやっていこうかな。
プロジェクトをまたいでの再利用にはコピペを使うという原始的なやりかたでやる。
で、僕のスキルが上がるか、あるいはGHCやCabalやStackの機能が追いつくかしたときにpackageを使うことにしよう。
古のやりかたでSetup.hsをコンパイルして実行するというやりかたならできるかもしれない。
Setup.hsを作ってパッケージを作ろうと思ったが、
% ./Setup configure --with-ghc=javascript-unknown-ghcjs-ghc --with-ghc-pkg=javascript-unknown-ghcjs-ghc-pkg --with-gcc=emcc --with-ld=emcc
% ./Setup build
...
wasm-ld: error: unknown file type: dist/build/Foo.o
...
のようにエラーになってしまう。GHCがJavaScriptを出力するときにどのような動作になっているのかを知る必要があるが、まあ、あとにしよう。
GHCのコードを読まざるを得ないだろうから。
ボタンをクリックした回数をラベルに表示するウェブアプリを作ってみた。
たとえばモジュールHelloひとつからなるパッケージを登録するとすると、つぎのようになる。
% javascript-unknown-ghcjs-ghc Hello.hs
% cp Hello.hi /home/foo/tmp/hello-0.1.0.0/
% emar qcls libHShello-0.1.0.0.a Hello.o
% mv libHShello-0.1.0.0.a /home/foo/tmp/hello-0.1.0.0/
以下のような内容のhello.confを作成する。
name: hello
version: 0.1.0.0
id: hello-0.1.0.0
key: hello-0.1.0.0
exposed-modules: Hello
import-dirs: /home/foo/tmp/hello-0.1.0.0
library-dirs: /home/foo/tmp/hello-0.1.0.0
hs-libraries: HShello-0.1.0.0
% javascript-unknown-ghcjs-ghc-pkg register hello.conf
上のhello.confのような内容を出力するコマンドを作った。
% javascript-unknown-ghcjs-ghc myPackageConf.hs
% cat packageTopDir.conf
/home/foo/tmp/
% cat exposedModules.conf
Hello
% ./mkPackageConf "hello" "0.1.0.0" exposedMOdules.conf
登録したパッケージを使おうとすると
getDeps: Couldn't find home-module:
Hello
みたいなエラーが出てコンパイルができない
どうやら、idとkeyをhello-0.1.0.0-inplaceのような名前にする必要があったようだ。
name: hello
version: 0.1.0.0
id: hello-0.1.0.0-inplace
key: hello-0.1.0.0-inplace
exposed-modules: Hello
import-dirs: ${pkgroot}/../lib/javascript-ghcjs-ghc-9.10.1/hello-0.1.0.0
library-dirs: ${pkgroot}/../lib/javascript-ghcjs-ghc-9.10.1/hello-0.1.0.0
library-dirs-static: ${pkgroot}/../lib/javascript-ghcjs-ghc-9.10.1/hello-0.1.0.0
hs-libraries: HShello-0.1.0.0
上の調査でソースコードにderiving Showとかprint文とかを書きまくったので、もう一度ソースコードを入手して、全体をインストールし直そうかな。
他のマシンに何回かインストールしたことで、どこにインストールしたらいいかみたいな話もかたまってきたし。~/.local/ghc/bin/に実行ファイルをコピーして、~/.local/ghc/lib/以下に設定ファイルを置いて、で~/local/bin/にsoft linkを置くのが良さそう。
あと、ソースコードは安定版ではなくて、GitHubから引っ張ってこようかな。進化が速そうなので。
最新のソースで試そうとしたらconfigureの段階でunknown argument: --no-as-neededで失敗したので、大人しく公開されたソースコードを試すことにする。
問題はそこではなくてHappyのバージョンだったようだ。
GitLabから持ってきた最新のソースだと、同様の問題がまた生じる。9.10.1だと平気。
以下のように-inplaceを付ける必要があった様子。GHC.StgToJSあたりが決め打ちで-inplaceの付く名前を使ってるってことなのかな。
name: hello
version: 0.1.0.0
id: hello-0.1.0.0-inplace
key: hello-0.1.0.0-inplace
exposed-modules: Hello
import-dirs: ${pkgroot}/../lib/javascript-ghcjs-ghc-9.11.20240705/hello-0.1.0.0-inplace
library-dirs: ${pkgroot}/../lib/javascript-ghcjs-ghc-9.11.20240705/hello-0.1.0.0-inplace
library-dirs-static: ${pkgroot}/../lib/javascript-ghcjs-ghc-9.11.20240705/hello-0.1.0.0-inplace
hs-libraries: HShello-0.1.0.0-inplace
あと、書いたかどうか忘れたけど、*.hiファイルとか*.oファイルを作るときには-package-nameオプションが必要。
% javascript-unknown-ghcjs-ghc -package-name hello-0.1.0.0-inplace Hello.hs
みたいにする。
いろいろ覚え書きしたけど、抜けてるところが多い。とくにパッケージ化については、独自のやりかたでインストールできるようにしたので、そのあたりを(まずは)メモりたい。