私は現在 C++ でアプリを作成していますが、その機能の一部は Haskell で作成したほうがよいことがわかりました。C コードから Haskell を呼び出す手順を見たことがありますが、C++ で同じことを行うことは可能ですか?
編集:明確にするために、私が探しているのは、Haskell コードを g++ が C++ のオブジェクト コードとリンクできる外部ライブラリにコンパイルする方法です。
更新:興味のある人のために、以下に実際の例を示しました(これも忘れないように)。
私は現在 C++ でアプリを作成していますが、その機能の一部は Haskell で作成したほうがよいことがわかりました。C コードから Haskell を呼び出す手順を見たことがありますが、C++ で同じことを行うことは可能ですか?
編集:明確にするために、私が探しているのは、Haskell コードを g++ が C++ のオブジェクト コードとリンクできる外部ライブラリにコンパイルする方法です。
更新:興味のある人のために、以下に実際の例を示しました(これも忘れないように)。
興味のある人には、これが私がついに機能するようになったテストケースです。
module Foo where
foreign export ccall foo :: Int -> Int
foo :: Int -> Int
foo = floor . sqrt . fromIntegral
#include <iostream>
#include "M_stub.h"
int main(int argc, char *argv[])
{
std::cout << "hello\n";
hs_init(&argc, &argv);
std::cout << foo(500) << "\n";
hs_exit();
return 0;
}
Windowsマシンでコンパイルとリンクを行いました。実行するコマンド(この順序で)は次のとおりです。
>ghc -XForeignFunctionInterface -c M.hs
>g++ -c test.cpp -I"c:\Program Files\Haskell Platform\2010.2.0.0\lib\include"
>g++ -o test.exe -DDONT_WANT_WIN32_DLL_SUPPORT M.o M_stub.o test.o -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\haskell98-1.0.1.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\random-1.0.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\time-1.1.4" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\process-1.0.1.3" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\directory-1.0.1.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\old-time-1.0.0.5" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\old-locale-1.0.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\filepath-1.1.0.4" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\Win32-2.2.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\bytestring-0.9.1.7" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\array-0.3.0.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\base-4.2.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\integer-gmp-0.2.0.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\ghc-prim-0.2.0.0" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib/gcc-lib" -lHSrtsmain -lHShaskell98-1.0.1.1 -lHSrandom-1.0.0.2 -lHStime-1.1.4 -lHSprocess-1.0.1.3 -lHSdirectory-1.0.1.1 -lHSold-time-1.0.0.5 -lHSold-locale-1.0.0.2 -lHSfilepath-1.1.0.4 -lHSWin32-2.2.0.2 -luser32 -lgdi32 -lwinmm -ladvapi32 -lshell32 -lshfolder -lHSbytestring-0.9.1.7 -lHSarray-0.3.0.1 -lHSbase-4.2.0.2 -lwsock32 -luser32 -lshell32 -lHSinteger-gmp-0.2.0.1 -lHSghc-prim-0.2.0.0 -lHSrts -lm -lwsock32 -u _ghczmprim_GHCziTypes_Izh_static_info -u _ghczmprim_GHCziTypes_Czh_static_info -u _ghczmprim_GHCziTypes_Fzh_static_info -u _ghczmprim_GHCziTypes_Dzh_static_info -u _base_GHCziPtr_Ptr_static_info -u _base_GHCziWord_Wzh_static_info -u _base_GHCziInt_I8zh_static_info -u _base_GHCziInt_I16zh_static_info -u _base_GHCziInt_I32zh_static_info -u _base_GHCziInt_I64zh_static_info -u _base_GHCziWord_W8zh_static_info -u _base_GHCziWord_W16zh_static_info -u _base_GHCziWord_W32zh_static_info -u _base_GHCziWord_W64zh_static_info -u _base_GHCziStable_StablePtr_static_info -u _ghczmprim_GHCziTypes_Izh_con_info -u _ghczmprim_GHCziTypes_Czh_con_info -u _ghczmprim_GHCziTypes_Fzh_con_info -u _ghczmprim_GHCziTypes_Dzh_con_info -u _base_GHCziPtr_Ptr_con_info -u _base_GHCziPtr_FunPtr_con_info -u _base_GHCziStable_StablePtr_con_info -u _ghczmprim_GHCziBool_False_closure -u _ghczmprim_GHCziBool_True_closure -u _base_GHCziPack_unpackCString_closure -u _base_GHCziIOziException_stackOverflow_closure -u _base_GHCziIOziException_heapOverflow_closure -u _base_ControlziExceptionziBase_nonTermination_closure -u _base_GHCziIOziException_blockedIndefinitelyOnMVar_closure -u _base_GHCziIOziException_blockedIndefinitelyOnSTM_closure -u _base_ControlziExceptionziBase_nestedAtomically_closure -u _base_GHCziWeak_runFinalizzerBatch_closure -u _base_GHCziTopHandler_runIO_closure -u _base_GHCziTopHandler_runNonIO_closure -u _base_GHCziConc_ensureIOManagerIsRunning_closure -u _base_GHCziConc_runSparks_closure -u _base_GHCziConc_runHandlers_closure -lHSffi
最後のg++コマンドのパラメーターの長いリストは、実行中のものです。
>ghc M.hs -v
次に、「***リンカー:」と表示されているコマンドをコピーします(最初のパラメーターの一部を削除する必要があります)。
結果:
>test
hello
22
編集:以下のTomerの回答もご覧ください。ここでの私の答えは、何が起こっているかの理論を説明していますが、実行の詳細の一部が不完全な場合がありますが、彼の答えは完全に機能する例です。
sclv が示すように、コンパイルは問題ないはずです。問題は C++ コードのリンクである可能性が高く、必要なすべてのランタイム ライブラリをリンクするのが少し難しくなります。問題は、Haskell プログラムを Haskell ランタイム ライブラリとリンクする必要があることと、C++ です。プログラムは C++ ランタイム ライブラリとリンクする必要があります。あなたが参照するWikiページで、彼らがそうするとき
$ ghc -optc -O test.c A.o A_stub.o -o test
C プログラムをコンパイルするには、実際には 2 つの手順を実行します。C プログラムをオブジェクト ファイルにコンパイルし、それをリンクします。書き出すと、次のようになります (私は GHC を話せないので、おそらく正しくないでしょう):
$ ghc -c -optc-O test.c -o test.o
$ ghc test.o A.o A_stub.o -o test
Cプログラムをコンパイルするとき、GHCはGCCのように振る舞います(そして、IIUCは機能的にGCCです)。ただし、それをリンクすると、Haskell ランタイム ライブラリも魔法のように含まれているため、GCC を直接呼び出した場合とは異なります。G++ は、C++ プログラムに対しても同じように機能します。リンカーとして使用される場合、C++ ランタイム ライブラリが含まれます。
したがって、前述したように、両方のランタイム ライブラリとリンクするようにコンパイルする必要があります。G++ を冗長モードで実行してプログラムをコンパイルおよびリンクすると、次のようになります。
$ g++ test.cpp -o test -v
何をしているかについての出力の長いリストを作成します。最後に、リンク先のcollect2
ライブラリを示す (サブプログラムとの) リンクを行う出力行が表示されます。これを単純な C プログラムのコンパイルの出力と比較して、C++ の違いを確認できます。私のシステムでは、追加されます-lstdc++
。
したがって、次のように Haskell/C++ 混合プログラムをコンパイルおよびリンクできるはずです。
$ ghc -c -XForeignFunctionInterface -O A.hs # compile Haskell object file.
$ g++ -c -O test.cpp # compile C++ object file.
$ ghc A.o A_stub.o test.o -lstdc++ -o test # link
そこでは、 を指定-lstdc++
したため、C++ ランタイム ライブラリがインクルードされ (-l
が正しい GHC 構文であると仮定します。確認する必要があります)、 とリンクしたためghc
、Haskell ランタイム ライブラリがインクルードされます。これにより、動作するプログラムが作成されます。
あるいは、GHC での出力調査と同様のことを行うことができ-v
、Haskell サポートのためにリンクする Haskell ランタイム ライブラリ (または複数のライブラリ) を特定し、プログラムを C++ にリンクするときにそのライブラリを追加することができます。純粋な C++ プログラムでは既に実行されています。(それが彼がしたことなので、その詳細についてはTomerの回答を参照してください。)
これは、トピックに関するチュートリアルです。
https://github.com/jarrett/cpphs
C++ からの Haskell の呼び出しと、Haskell からの C の呼び出しについて説明します。
Haskell は C から呼び出せるので、C++ から呼び出せない理由はありません。一方、Haskell から C++ を呼び出すのははるかに難しく、通常は C ラッパーが必要です。
編集して展開します。指示が間違っているか不完全です。それらはウィキページです。GHC マニュアルを直接見てください: http://www.haskell.org/ghc/docs/6.12.2/html/users_guide/ffi-ghc.html
ここでは、関数をエクスポートする方法と、独自のメインを使用する方法について説明します。「他の言語、たとえばC」と書かれていることに注意してください。これは、エクスポートしているバニラ C 関数を呼び出すことができ、HsFFI.h が提供する任意の言語 (およびコンパイラ) からこれを実行できるためです。これは言語に依存せず、コンパイラにも依存しません。必要なのは、C++ コンパイラ (g++ など) が確実に提供する、システムの標準呼び出し規則を使用して C 関数を呼び出す機能だけです。