スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Cなどで書かれたプログラムからHaskellを使う(メモ)+Xcodeのプロジェクトに組み込むときのメモ

ある種の処理を書く時にHaskellは便利だが、プログラムの他の部分はCなどの他の言語で書きたい場合がある。 そこで、Haskellで動的ライブラリ(.soや.dylib)を作り、他のプログラムから呼び出せるようにしたいと思った。

Haskell側ではforeign exportで関数をエクスポートすればよい。 foreign exportの入ったモジュールをコンパイルすると*_stub.h,*_stub.cというファイルが生成される…と思ったら現在のGHCでは_stub.cの方は生成されない?

C側のプログラムからは、生成された_stub.hを#includeすればHaskellで書かれた関数のC言語でのプロトタイプが見える…のだが、この_stub.hからはHsFFI.hというHaskell処理系の(?)ヘッダで、単体のライブラリとして配布する際に依存性があると邪魔だ。なので、自前でヘッダファイルを書くか、Haskellで書かれた関数をラップする関数をCで書くかするといいと思う。

また、Haskellの関数を使う前にHaskellのランタイムを初期化する必要がある。 Calling Haskell from C - HaskellWiki8.2. Using the FFI with GHCを参考に初期化ルーチンを書こう。 __attribute__((constructor))__attribute__((destructor))をつけておけばライブラリの使い手でいちいち初期化ルーチンを呼ぶ必要がなくて楽かもしれない。

ライブラリのコードとしてはCのコードとHaskellのコード両方が含まれる。どっちもまとめてGHCに渡してしまうといいだろう:

ghc -O2 --make -no-hs-main -optl '-dynamiclib' -o libHogehoge.dylib Hogehoge.hs Higehige.c

当初試したときは、リンク時に_environが見つからないというようなエラーが出たが、この問題はGHCの最新バージョンでは直っているらしく、Haskell Platform 2012.4(GHC 7.4.2)をインストールしたら解決した。

自分の場合は、ライブラリを呼ぶ側のプログラムはCocoaアプリケーションで、Xcodeで開発している。それで、Xcodeのビルドボタンを押すとHaskellのライブラリも一緒にビルドされるようにしたい。 ビルド中に上記のコマンドラインが実行されるようにしたいのだが、Haskell用のBuild Ruleを追加して…というのは難しそうだったのでMakefileを書いてExternal Build Systemとしてターゲットを作った。

Makefileの内容はこんな感じで:

PRODUCT = $(BUILT_PRODUCTS_DIR)/libHogehoge.dylib

all: $(PRODUCT)

$(PRODUCT): Hogehoge.hs Higehige.c $(BUILT_PRODUCTS_DIR)
	ghc -c -O2 --make -outputdir $(DERIVED_FILE_DIR) -o $@ Hogehoge.hs
	ghc -O2 --make -no-hs-main -optl '-dynamiclib' -outputdir $(DERIVED_FILE_DIR) -o $@ Hogehoge.hs Higehige.c
	install_name_tool -id @executable_path/libHogehoge.dylib $@

$(BUILT_PRODUCTS_DIR):
	mkdir -p $@

$(BUILT_PRODUCTS_DIR)$(DERIVED_FILE_DIR)はXcodeがコマンドを呼び出す際に設定してくれる環境変数。 Higehige.cから_stub.hを参照する場合、.hsと.cを一度にghcに渡すと_stub.hが存在しない場合エラーになるようで、先に.hsだけをコンパイルして_stub.hが確実に存在するようにしている。なんだか無駄なようで、自分のやり方が悪いのかもしれない。 ライブラリを.app内に含めることを考えて、リンク後にinstall_nameを設定している。

Xcode側の設定は、External Build Toolとして作ったターゲット(仮にHigehigeとする)の、DirectoryにMakefileがあるディレクトリを設定しておく。ソースコード内の位置指定に$(SRCROOT)が使える。 また、プロジェクトのファイルとして、生成されるlibHigehige.dylibを追加しておく。ビルドしてできたファイルをXcodeに追加して、プロパティーのLocationをRelative to Build Productsに設定すればいい感じになるだろう。

主となるアプリケーションの設定としては、Build PhasesのTarget DependenciesにHigehigeを追加しておく。 それから、先に追加したlibHigehige.dylibをリンクするように設定する。 あと、ビルド後にlibHigehige.dylibをアプリケーションバンドル内にコピーするBuild Phaseを追加しておく。

我ながらかなり読みにくい文章になってしまった。CからHaskellを呼ぶ話と、XcodeでExternal Build Toolを使ってファイルをビルドする話が混ざっている気がする。 しかし、読みやすい文章を心がけたりスクリーンショットを載せたりしてがんばると、ただでさえ半年間更新していないブログの更新がますます億劫になってしまうのは間違いない。だからこのぐらいの適当さでいいのだ、ということにしておく。

スポンサーサイト

テーマ : プログラミング | ジャンル : コンピュータ

プロフィール

minoki

Author:minoki
好きなプログラミング言語:
Haskell,Lua
GitHubアカウント
Twitter

最新記事
月別アーカイブ
カテゴリ
検索フォーム
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。