ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

HaskellコミュのCからHaskellを呼ぶ

  • mixiチェック
  • このエントリーをはてなブックマークに追加
C/C++からHaskellコードを呼びたいのですが、
FFIを利用して、CからHaskellを呼ぶというのは、コンパイラはghcなどのHaskellコンパイラを呼ぶしかないのでしょうか?

なんとか、gccやVisualStudioからHaskellの関数を呼ぶことはできないのでしょうか?

http://d.hatena.ne.jp/goth_wrist_cut/20071231/1199085347
などを参考にしています。

コメント(11)

どういうことをしたいのでしょうか? Haskell でライブラリを作って、それを C/C++ から予備たいということであれば、GHC のマニュアルに方法が書いてあります。日本語訳が公開されていますので、そちらを参考にすると良いでしょう。

http://www.kotha.net/ghcguide_ja/6.8.3/ffi-ghc.html#ffi-library
http://www.kotha.net/ghcguide_ja/6.8.3/win32-dlls.html

なお、マニュアルにもありますが、現在の GHC では共有ライブラリ(DLL)の扱いに少し難があります。このあたりの問題は、次のメジャーバージョンアップである GHC 6.12 で解決する見込みです。

http://hackage.haskell.org/trac/ghc/wiki/Status/Releases#Beyond6.10
http://hackage.haskell.org/trac/ghc/wiki/Status/October08#TheGHC6.12branch
shelarcyさん ありがとうございます。

C++でOpenGLを使ったプログラムを組んでいるます。普段は、xcodeやVCを使っています。
そこから、Haskellで書いた関数を呼びたいのです。

shelarcyさんの紹介していただいたページ読みましたが、
具体的には、どのようにすればいいのでしょうか。
(コンパイルの詳しい工程は理解できてないです。。)

ghc --make -fffi foo.hs
とやって、*_stub.* を作った後、
さらに、_stub.hで出来た関数を呼ぶような .c ファイルを作成して、それを使って、
ghc -c fromHaskell.c
で、.oファイルを生成したのですが、
これを単純に、xcode(gcc?)などでリンク時にリンクするだけではいけないのでしょうか?
これだと、まだ、細かいリンクエラーがたくさん出てしまいます。
> (コンパイルの詳しい工程は理解できてないです。。)

ええと、もしかしてこれまで C/C++ でライブラリを作成したことがないのでしょうか? もしそうした経験がないようでしたら、この機会に一回やってみることをお勧めします。特に Visual Studio や Xcode などの IDE の機能に頼っての作成だけでなく、make などの手書きファイルを使ってのライブラリ作成を試してみると良いと思います。

C/C++ から Haskell の関数を呼ぶことは 、C/C++ から C/C++ の関数を呼ぶことの応用なので、基本を知っておかなければこの先何度か躓くことになるでしょう。(Windows 関係は色々とややこしい部分がありますし)。


> ghc -c fromHaskell.c
> で、.oファイルを生成したのですが、
> これを単純に、xcode(gcc?)などでリンク時にリンクするだけではいけないのでしょうか?

ここに書かれているように、foo_stub.o や foo.o もリンクしましょう。

http://www.kotha.net/ghcguide_ja/6.8.3/win32-dlls.html#win32-dlls-foreign

foo_stub.h で参照する関数本体は foo_stub.o オプションに定義されていますし、foo_stub.* も Haskell で定義されている foo.o の関数を C から参照するためのものなので、foo.o がなければ機能しません。従って、fromHaskell.o をリンクするだけではリンクエラーが出てしまうことになります。

あと、細かい点ですが、GHC 6.10.1 から -fffi オプションは非推奨になりました。今後のメジャーバージョンアップによって、このオプションは削除される予定です。

http://www.haskell.org/ghc/docs/6.10.1/html/users_guide/release-6-10-1.html#id2565141

ですので、-XForeignFunctionInterface を使うか、

ghc --make -XForeignFunctionInterface foo.hs

ソースコードの最初の行に LANGUAGE 指示文を使って以下のように記述してください。

{-# LANGUAGE ForeignFunctionInterface #-}

-X オプションや LANGUAGE 指示文は GHC 6.8.x でも利用可能です。(手前味噌ですが、-X オプションや LANGUAGE 指示文の例)

http://itpro.nikkeibp.co.jp/article/COLUMN/20080902/313965/?ST=ittrend&P=5
あーっと、うっかり忘れていました。

foo.o をリンクするときに参照する必要のある Haskell 関数が、libHS<パッケージ名>-<パッケージのバージョン>.a に収録されているため、そちらもリンクしなければやはりエラーメッセージが出てきますね。

そこで発生するエラーをいちいち全部追いかけていくのは大変なので、素直に Haskell でライブラリを作って、そこから利用するようにした方が良いのではないでしょうか?
shelarcyさん

ありがとうございます。

はい。IDEを使ったライブラリの作成などはやったことがあるのですが、makefileや、gccを直接使ったコンパイルはほとんどしたことはありません。。

少しずつ勉強していますが、なかなか出来てません。
ghcでは、gccと同じように(gccを呼んでいる?)、.cファイルのコンパイルが出来る、、みたいな事もよく理解していませんでした。
となると、gccの使いかたをよく理解していないと出来ませんね・・・


>foo.o をリンクするときに参照する必要のある Haskell 関数が、libHS<パッケージ名>-<パッケージのバージョン>.a に収録されているため、そちらもリンクしなければやはりエラーメッセージが出てきますね。

foo.o foo_stub.o fromHaskell.oの3種をリンクに追加し、また、
/opt/local/lib/ghc-6.8.3
内にある、libHS*.aをいろいろ追加してみたのですが、まだリンクエラーが消えません。。


>そこで発生するエラーをいちいち全部追いかけていくのは大変なので、素直に Haskell でライブラリを作って、そこから利用するようにした方が良いのではないでしょうか?

というのは、Haskellで、ghcでのコンパイルで、すべてがリンクされたライブラリを作成出来るという事でしょうか?
いろいろやってみた結果、
外部ライブラリのlibgmp.aをリンクに加え、

もう一つ、致命的だったのが、ハスケルの関数を呼ぶための、
fromHaskell.cと、fromHasekell.hの中で、

#ifdef __cplusplus
extern "C" {
#endif

で、Cの関数だということを加えることで、最終的なコンパイル・実行まで出来ました。


今度、Windowsでも同様のことをやってみることに加え、
makefileや、gccについてもこれから勉強したいと思います。

ありがとうございました。
> ghcでは、gccと同じように(gccを呼んでいる?)、.cファイルのコンパイルが出来る、、みたいな事もよく理解していませんでした。

はい、gcc を呼んでコンパイルさせています。


> Haskellで、ghcでのコンパイルで、すべてがリンクされたライブラリを作成出来るという事でしょうか?

そうです。GHC を含めた最近の Haskell 処理系にはパッケージシステムが付属していて、パッケージ内の依存関係の記述からリンク時に必要な(Haskell および外部の)ライブラリを探し出してくれます。

http://www.kotha.net/ghcguide_ja/6.8.3/packages.html

ただし、base などの一部の例外を除き、ほとんどのパッケージは -package オプションを使って使用しないとビルド時にリンクされないので注意してください。

(一応、モジュール名の衝突がおこっていなければ、 --make オプションを使って推論させることもできます。
http://itpro.nikkeibp.co.jp/article/COLUMN/20070501/269948/?ST=ittrend&P=2
http://www.kotha.net/ghcguide_ja/6.8.3/modes.html#make-mode )
すべてをリンクしてしまえるというのは、
foo.hsから、*stub.cや*stub.hを作る時でしょうか?
それとも、それらを参照する.c ファイルをコンパイルする時でしょうか?

今やっているのは、
$ ghc --make foo.hs
で、foo.oと*stub.*を作り、
$ ghc --make fromHaskell.c
として、fromHaskell.oを作っていますが、
.oファイルのファイルサイズはどれも数kb 以内です。


(ちなみに、MacOSX 10.5.5、  ghc 6.8.3  gcc 4.0.1 を使っています。
http://www.kotha.net/ghcguide_ja/6.8.3/ffi-ghc.html
ここに出てくるFooモジュールを想定してます。)

(http://www.kotha.net/ghcguide_ja/6.8.3/options-phases.html#options-linker
ここを見ると、OSXではリンクの工程が特殊らしいのですが、、OSXでは静的ライブラリが使用されないのでしょうか。)
> それとも、それらを参照する.c ファイルをコンパイルする時でしょうか?

はい、コンパイル時ではなく、実行可能ファイルやライブラリを構築するリンク時になっているはずです。特に -c オプションを使うとマニュアルにもあるようにリンクを行わないので、注意が必要です。

> Mac OS X

Mac OS X 向けに作られているライブラリが、Framework という独自の仕様を使って収められているためですね。

> OSXでは静的ライブラリが使用されないのでしょうか。

もちろん、静的リンクライブラリが提供されていれば、静的リンクライブラリを使用することもできます。ただし、Mac OS X では動的リンクライブラリしか提供されていないことも多々あるようです。ls /usr/lib などとしてみると、良く分かると思います。
おっと、意図を取り違えていました。また、最初の返事の意味が取りにくいですね。なので書き直します。

GHC では依存するライブラリを、コンパイル時ではなくリンク時に参照しに行きます。なので、その C ファイルのコンパイルが実行可能ファイルやライブラリを作成するものであれば、その時に全てのライブラリをリンクしてくれるはずです。

単に C ファイルをコンパイルしてオブジェクト・ファイルを作る場合には、gcc で -c オプションをつける場合や、Haskell のソースコードを -c オプションをつけてコンパイルする場合と同様に、コンパイルが行われるだけでライブラリのリンクは一切行われないので注意してください。

よって、おそらく、foo.o も foo_stub.o も fromHaskell.o も依存するライブラリの実体を含んではいないでしょう。Windows の DLL の作成方法の説明にあるように、これらのオブジェクトを ghc を使ってリンクさせれば、その時に初めて依存するライブラリの実体がリンクされるという動作になると思います。
ただ……マニュアルをよくよく見てみると、Windows で DLL を作る場合以外でのライブラリ作成のコマンド例が一切示されていませんね。

もしかすると、GHC 6.12 の(新しい)「共有リンクライブラリ作成対応」が入るまでは、Mac を含めた unix 環境で ghc を使って直接ライブラリを作成することはできないのかもしれません。もしそうであるなら、面倒ですがパッケージ内に記述されているライブラリファイルを別の手段でリンクして下さい。現状では上で主張したライブラリ化のメリットが失われてしまいますが。
(普段 Haskell ライブラリを作る場合には、代わりに Cabal というビルドシステムを使っています。ただ、このビルドシステムでは今のところ C/C++ のライブラリを作る方法は提供されていません。)

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Haskell 更新情報

Haskellのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング