ghcjsをhardened profileのGentooにインストールするには

今年もよろしくおねがいします.


大晦日にghcjsのREADMEが更新され,ghc-7.6ベースになったり,これまで煩雑だったインストール作業がスクリプト化されたりするなど,いろいろと変更があった.実にはタイミングの悪いことに,このREADME更新が行われる直前,半年振り?くらいにghcjsをビルドしてみようか*1と作業し初めてしまっており,何かインストール手順に記載されてないパッケージに依存するようになってるなぁとかで試行錯誤したりしてイロイロとハマっていたのだが,なんのことはない,ちょっと大きな変更の過渡状態で作業していたと知ってガックリ.

で,例によって?hardened profileなGentooだとインストーラスクリプトそのまま走らせてもビルドエラーで入らないので,どうしたかについて備忘録として記載しておく.ちなみに実験環境はVirtualBox上のGentoo amd64 hardened.ちなみにdefault profileについてはインストール試していないが,もしそっちで何かダメでも同様の方法で動かせるようにはなるはずだろう.

基本はPIE/SSPビルドを無効にするにはどうすればよいですか?の項にある作業をghcjs公式のインストール手順・インストーラスクリプトに挿し込むことになる.ちなみにこの作業はghcをemergeする際にも行われている.ルートになって下記手順でghcビルド時のオプションがどうなるか確認できる.

ebuild /var/lib/layman/haskell/dev-lang/ghc/ghc-7.6.1.ebuild configure
cat /var/tmp/portage/dev-lang/ghc-7.6.1/work/ghc-7.6.1/mk/build.mk

build.mkの内容はたとえばこんなカンジになっている.

# Gentoo changes
docdir = /usr/share/doc/ghc-7.6.1
htmldir = /usr/share/doc/ghc-7.6.1
SRC_HC_OPTS+= -optc-march=native -opta-march=native -optc-nopie -optl-nopie -optc-fno-stack-protector -optc-Wa,--noexecstack -opta-Wa,--noexecstack
SRC_CC_OPTS+=-march=native -pipe -O2 -march=native -march=native -nopie -fno-stack-protector -Wa,--noexecstack -Wa,--noexecstack
SRC_LD_OPTS+= -nopie
BUILD_DOCBOOK_PDF  = NO
BUILD_DOCBOOK_PS   = NO
BUILD_DOCBOOK_HTML = NO
HADDOCK_DOCS       = NO
SRC_HC_OPTS+=-w

基本この条件をそのままghcjsビルド時にも与えてあげればよい.が,一般ユーザのHOME以下に一般ユーザの権限でビルドして入れるので,docdir/htmldirの指定はこのままだとマズい.消してしまおう.

また,SRC_HC_OPTSはインストーラスクリプトghcjs-build.sh内からcabalが呼ばれるときにも--ghc-optionsとして与えてあげる必要がある.(これは設定次第で不要になるんじゃないかなとも思っている*2のだが,追い切れていない.だれか知ってる人情報キボン)

cd
git clone https://github.com/ghcjs/ghc
cd ghc
git checkout ghc-7.6
./sync-all -r https://github.com/ghc get
./sync-all -r https://github.com/ghcjs --ghcjs get
./sync-all checkout ghc-7.6
cabal update
./unpack.sh
cat > mk/build.mk <<EOF
SRC_HC_OPTS+= -optc-march=native -opta-march=native -optc-nopie -optl-nopie -optc-fno-stack-protector -optc-Wa,--noexecstack -opta-Wa,--noexecstack
SRC_CC_OPTS+=-march=native -pipe -O2 -march=native -march=native -nopie -fno-stack-protector -Wa,--noexecstack -Wa,--noexecstack
SRC_LD_OPTS+= -nopie
BUILD_DOCBOOK_PDF  = NO
BUILD_DOCBOOK_PS   = NO
BUILD_DOCBOOK_HTML = NO
HADDOCK_DOCS       = NO
SRC_HC_OPTS+=-w
EOF
nano -w ghcjs-build.sh # cabal/cabal-meta に --ghc-options="SRC_HC_OPTSの内容"を追加する.
export PATH=$HOME/.cabal/bin:$PATH # ghcjs-build.shはこのパスが通っていることを前提としてるっぽい.
./ghcjs-build.sh

でもってこのインストールスクリプト,結構時間がかかるため,ある程度覚悟を決めるか寝るか別の作業をしよう.個人的には寝るのをお勧めする.仮想マシン環境とはいえ今回の実験環境は現時点ではそれなりにパワーのあるマシン(Intel(R) Core(TM) i7-3960X CPU @ 3.30GHzで仮想環境として割り振りはCPU8コア&メモリ8GB)と言えるほうだが,それでも以下のように1.5hかかっている.

./install-ghcjs.sh  9672.08s user 3072.23s system 234% cpu 1:30:29.01 total

通常何もしなければghcjsは使われないが,

export PATH=$HOME/ghcjs/bin:$PATH

するとghcjsが有効な状態になる.

一応これまででghcjsインストール完了ではあるのだが,webkitなども入らないことには十全にghcjsを使うことができないので,exampleまで入れる.というかそこにも罠があるのでそっちまで解説しなければ片手落ちだったりする.今回は事前にwebkit-gtk-1.8.3-r200をemergeしている.gtk+-2.24.12なのでcabal-meta install時に-fgtk3は無し,また,webkit-1.10系じゃないので-fwebkit1.8を付けている.

export PATH=$HOME/ghcjs/bin:$PATH
git clone https://github.com/ghcjs/ghcjs-examples.git
cd ghcjs-examples
cabal-meta install --force-reinstalls -fwebkit1-8 --ghc-options="-optc-march=native -opta-march=native -optc-nopie -optl-nopie -optc-fno-stack-protector -optc-Wa,--noexecstack -opta-Wa,--noexecstack"

とやっても,残念なことに失敗しているハズだ.これは gtk系hackage特有の問題?に遭遇している.gtk系hackageは通常のsetupの他にsetup-wrapperというものを作ってビルドを行うようになっているのだが,cabal installで--ghc-optionsに指定した内容が奥のほうまで届かないようなのだ.バグ臭い.

なので,一度周辺をクリアして, --ghc-options を強制的に挿し込むんでもらうようにコードを弄った上でリトライする.

rm -rf vendor/*/dist vendor/gtk2hs/*/dist
sed -i 's/, setupDir]/, setupDir, "-optc-march=native", "-opta-march=native", "-optc-nopie", "-optl-nopie", "-optc-fno-stack-protector", "-optc-Wa,--noexecstack", "-opta-Wa,--noexecstack"]/' vendor/gtk2hs/*/SetupWrapper.hs vendor/webkit/SetupWrapper.hs vendor/webkit-javascriptcore/SetupWrapper.hs
cabal-meta install --force-reinstalls -fwebkit1-8 --ghc-options="-optc-march=native -opta-march=native -optc-nopie -optl-nopie -optc-fno-stack-protector -optc-Wa,--noexecstack -opta-Wa,--noexecstack"

途中で

gtk2hsC2hs: UName: root name supply used after saving

が原因のエラーになることがあるが,気にせずもう一度叩くとキモいけど通るようになるとのことなのでそうすると確かにキモいけど何故か通る.

ghcjs-min ~/.cabal/bin/ghcjs-hello

で,~/.cabal/bin/ghcjs-hello.trampoline.jsexe 以下にJavaScriptが吐かれているのが確認できる.あとはコイツをブラウザから見える状態にしてやればよい.

ghcjs有効状態にしてcabal installでパッケージを入れると,各モジュール毎に対応するJavaScriptもモリモリ吐き出していく様は圧巻. cabal install --helpを見ると--enable/disable-java-scriptなどというオプションがあるのもおもしろい.

ghcjsはまだ発展途上だが,fay等と比べ,

  • 既存のパッケージが通常通りcabal installして使える
  • webkitによるStandalone BinaryでWebサーバに置かずとも動作を確認できる

など優れた点が多い,逆に,

  • FFIが弱い(=既存のJavaScriptライブラリは使いにくい)

など力弱い点もあるが,むしろunsafeで名状し難いJavaScript跳梁跋扈する深淵の覗き窓*3を作るくらいなら弱いままでも良いくらいという向きもあるだろう.とにかく,ghcjsの今後ますますのご発展を心よりお祈り申し上げます.

*1:だいたい[http://blog.konn-san.com/article/20121225/fay-introduction:title=こんさんの記事]のせい

*2:通常のcabalコマンドがこの指定を必要としていないので

*3:ああ!窓に!窓に!