GHC(および、GHCでコンパイルされた実行ファイル)をcygwinで使う

背景

cygwinツール群は、unixソフトウェアをwindowsに移植する作業を簡単にするために、windowsライブラリの上にunix風のAPIを提供するものである。このために、unix形式のディレクトリ階層をなんらかのルートディレクトリ(典型的にはC:\cygwin\/になる)の下に導入する。さらに、cygwin APIに対してビルドされたもの(cygwinのツール群やcygwinのghcでコンパイルされたプログラムを含む)は、/をファイルシステムの根だと認識し、典型的なunix環境で動作していると思い込む。そして、/bin/usr/includeなどを、windowsシステム上での実際の位置(おそらくC:\cygwin\binC:\cygwin\usr\include)に構うことなく見つける。

問題

GHCは、デフォルトで、もはやcygwinに依存しておらず、ネイティブのwindowsプログラムである。GHCはmingwでビルドされ、Haskellのソースをコンパイルするときにはmingwのghcを使う。(cygwinのbashから呼んだ場合でもそうである)。しかし、問題は、通常のwindowsプログラムと同様、GHCも、GHCが生成したプログラムも、cygwinの疑似unix階層構造について知らないということである。GHCはディレクトリ区切りとして「/」と「\」の両方を喜んで受け付けるが、/home/joe/Main.hs/bin/bashのようなものをどうやって見つけるかは知らない。このため、GHCをcygwinのbashから使ったり、cygwinで走っているmakeセッションから呼んだりすると、いろいろな楽しいことが起こる。

するべきこと

  • make、configure、coをするときに、GHC(またはGHCでコンパイルされたプログラム)に渡される可能性がある場面では、絶対パスを使ってはいけない。相対パスは、cygwinのツール群もうまく扱えるし、GHCは「/」をパス区切りとして受け付けるので、問題ない。さらに、相対パスは、cygwinのルートディレクトリがどこにあるかに依存しないし、ソースツリーがどのパーティション・ネットワークドライブにあるか、ということも、一旦そこに「cd」してしまえば関係ない。

  • 絶対パスを使わなければならない場合(makefileの階層やconfigureスクリプト中の一見無害なROOT=`pwd`に注意)のために、cygwinにはcygpathというツールがあり、cygwinのunix形式のパスを実際のwindows形式のものに変換することができる。cygwinツールの大部分は実際にはwindows形式のパスも受け付ける(ただし「\」をエスケープするか「\」の代わりに「/」を使う必要がある)ので、常にこれを使っていて問題ないはずである。unix形式のパスに依存するなんらかのパス操作を行うツールを使いたい場合(一つの楽しい例は「:」がパス区切りとして解釈されてしまう場合である)でも、パスがGHCやその仲間たちに渡される直前にcygpathで変換することができる。

  • もしあなたがcygpathを持っていないなら、おそらくあなたはcygwinを持っていないので、問題ない。ただし、複数のプラットフォームで使えるビルド過程を書きたいなら話は別である。この場合でも相対パスを使えば良いが、絶対パスを使う必要があり、しかもプラットフォームごとに異なるツールを使いたくない場合、短いHaskellプログラムを書いてカレントディレクトリを出力させるという方法がある。(この考えを出したGeorge Russellに感謝)。それをGHCでコンパイルして実行すれば、GHCが見ているファイルシステムの姿(これはGHCがcygwinのgccでコンパイルされたか、mingwのgccか、それとも本物のunixシステムのgccかに依存する)が分かる。その小さなプログラムにパス中の「\」をエスケープさせることもできる。バナーが表示されるのと、起動に時間がかかることを除けば、以下のようなものでも良い。

      $ echo "Directory.getCurrentDirectory >>= putStrLn . init . tail . show " | ghci