IT이야기

C ++ 코드에서 Haskell 호출

cyworld 2021. 3. 30. 22:04
반응형

C ++ 코드에서 Haskell 호출


저는 현재 C ++로 앱을 작성 중이며 일부 기능이 Haskell에서 더 잘 작성된다는 것을 알았습니다. C 코드에서 Haskell호출하는 방법에 대한 지침을 보았지만 C ++에서도 동일한 작업을 수행 할 수 있습니까?

편집 : 명확히하기 위해 내가 찾고있는 것은 Haskell 코드를 g ++가 C ++의 개체 코드와 연결할 수있는 외부 라이브러리로 컴파일하는 방법입니다.

업데이트 : 나는 관심있는 다른 사람을 위해 아래에 작업 예제를 올렸습니다 (또한 잊지 않을 것입니다).


편집 : 아래 Tomer의 답변도 볼 수 있습니다. 여기에 내 대답은 무슨 일이 일어나고 있는지에 대한 이론을 설명하지만 실행에 대한 세부 사항이 불완전 할 수 있지만 그의 대답은 완전한 작업 예입니다.

sclv에서 알 수 있듯이 컴파일은 문제가되지 않습니다. C ++ 코드를 링크하는 데 어려움이있을 수 있으며 여기에서 필요한 모든 런타임 라이브러리를 링크하는 데 약간의 어려움이있을 것입니다. 문제는 Haskell 프로그램을 Haskell 런타임 라이브러리 및 C ++와 링크해야한다는 것입니다. 프로그램은 C ++ 런타임 라이브러리와 연결되어야합니다. 참조하는 Wiki 페이지에서

$ ghc -optc -O test.c A.o A_stub.o -o test

C 프로그램을 컴파일하기 위해 실제로 두 단계를 수행합니다. C 프로그램을 객체 파일로 컴파일 한 다음 함께 연결합니다. 작성하면 다음과 같습니다 (GHC를 말하지 않기 때문에 아마도 옳지 않을 것입니다).

$ ghc -c -optc-O test.c -o test.o
$ ghc test.o A.o A_stub.o -o test

GHC 는 C 프로그램을 컴파일 할 때 GCC 처럼 작동합니다 (그리고 IIUC는 기능적 으로 GCC 임). 그러나 링크 할 때 GCC를 직접 호출하는 경우와는 다릅니다. 마법처럼 Haskell 런타임 라이브러리도 포함하기 때문입니다. 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 런타임 라이브러리를 포함합니다. 이로 인해 프로그램이 작동해야합니다.

또는 -vGHC 를 사용하여 출력 조사와 유사한 작업을 수행하고 Haskell 지원을 위해 연결된 Haskell 런타임 라이브러리 (또는 라이브러리)를 파악한 다음 프로그램을 C ++와 연결할 때 해당 라이브러리를 추가 할 수 있습니다. 순수한 C ++ 프로그램을 위해 이미하고 있습니다. (자세한 내용은 Tomer의 답변을 참조하십시오. 그게 그가 한 일이기 때문입니다.)


관심있는 사람에게는 이것이 내가 마침내 작업 한 테스트 케이스입니다.


M.hs

module Foo where

foreign export ccall foo :: Int -> Int

foo :: Int -> Int
foo = floor . sqrt . fromIntegral

test.cpp

#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

그런 다음 "*** Linker :"(첫 번째 매개 변수 중 일부를 제거해야 함)라고 표시된 명령을 복사합니다.


결과:

>test
hello
22

다음은 주제에 대한 자습서입니다.

https://github.com/jarrett/cpphs

It covers calling Haskell from C++ and calling C from Haskell.


Since you can call Haskell from C, there's no reason you can't call it from C++. Calling C++ from Haskell, on the other hand, is much harder and usually requires a C wrapper.

Edit to expand. The instructions are wrong to incomplete. They're a wiki page. Look directly at the GHC manual: http://www.haskell.org/ghc/docs/6.12.2/html/users_guide/ffi-ghc.html

This describes how to export functions, and how to use your own main. Note where it says "some other language, say C." It says this because you can do this from any language (and compiler) that can invoke the vanilla C functions that you're exporting, and that HsFFI.h provides. This is language agnostic, and compiler agnostic. All it requires is the ability to invoke C functions using the standard calling conventions on your system, which a C++ compiler (such as g++) certainly provides.


cabal 2.0 added the "foreign-library" feature which seems to solve the linker issues as well as making the whole build process much more pleasant in general.

I put together a short example tutorial https://github.com/pdlla/haskell-ffi-cabal-foreign-library-examples

ReferenceURL : https://stackoverflow.com/questions/3859340/calling-haskell-from-c-code

반응형