Подтвердить что ты не робот

Вызов Haskell из кода С++

В настоящее время я пишу приложение на С++ и обнаружил, что некоторые функции будут лучше написаны в Haskell. Я видел инструкции вызов Haskell из кода C, но можно ли сделать то же самое с С++?

EDIT: Чтобы уточнить, что я ищу, это способ скомпилировать код Haskell во внешнюю библиотеку, которую g++ может связывать с объектным кодом из С++.

ОБНОВЛЕНИЕ: Я привел рабочий пример ниже для всех, кого это интересует (также я не забуду).

4b9b3361

Ответ 1

Изменить: Вы также должны увидеть ответ Tomer ниже. Мой ответ здесь описывает теорию того, что происходит, но у меня могут быть некоторые детали исполнения неполные, тогда как его ответ - полный рабочий пример.

Как указывает sclv, компиляция не должна быть проблемой. Трудность, по-видимому, связана с кодом С++, и здесь вам будет немного сложно получить все необходимые библиотеки времени выполнения. Проблема состоит в том, что программы Haskell должны быть связаны с библиотеками времени исполнения Haskell, а С++ программы должны быть связаны с библиотеками времени выполнения С++. На странице 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

GGC просто выполняет роль GCC (и, IIUC, функционально GCC) при компиляции программы C. Однако при связывании он отличается от того, что происходит, если вы вызываете GCC напрямую, потому что он также магически включает библиотеки времени исполнения Haskell. g++ работает одинаково для программ на С++ - когда он используется в качестве компоновщика, он включает библиотеки времени выполнения С++.

Итак, как я уже упоминал, вам нужно скомпилировать таким образом, что связывается с обеими библиотеками времени исполнения. Если вы запускаете g++ в подробном режиме для компиляции и ссылки на программу, например:

$ g++ test.cpp -o test -v

он создаст длинный список результатов о том, что он делает; в конце будет строка вывода, где она связывает (с подпрограммой collect2), указывающую, к каким библиотекам она привязывается. Вы можете сравнить это с выходом для компиляции простой программы на C, чтобы увидеть, что отличается для С++; в моей системе он добавляет -lstdc++.

Таким образом, вы должны иметь возможность компилировать и связывать вашу смешанную программу Haskell/С++ так:

$ 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++, он будет включать в себя библиотеку времени выполнения С++ (предполагая, что -l - это правильный синтаксис GHC, вам нужно проверить) и потому, что вы связались с ghc, он будет включать библиотеку времени исполнения Haskell. Это должно привести к рабочей программе.

В качестве альтернативы вы можете сделать что-то похожее на исследование вывода -v с помощью GHC и выяснить, какую библиотеку времени исполнения Haskell (или библиотеки) он связывает для поддержки Haskell, а затем добавить эту библиотеку при связывании вашей программы с С++, так же, как вы уже делаете для чистых программ на С++. (См. Tomer для получения подробной информации об этом, так как это он сделал.)

Ответ 2

Для всех, кого это интересует, это тестовый пример, в котором я наконец-то работал:


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

Ответ 3

Это учебник по теме:

https://github.com/jarrett/cpphs

Это касается вызова Haskell из C++ и вызова C из Haskell.

Ответ 4

Поскольку вы можете вызывать Haskell с C, нет причин, по которым вы не можете называть его из С++. С другой стороны, вызов С++ из Haskell намного сложнее и обычно требует оболочки C.

Изменить, чтобы развернуть. Инструкции неверны для неполного. Это страница вики. Посмотрите прямо на руководство GHC: http://www.haskell.org/ghc/docs/6.12.2/html/users_guide/ffi-ghc.html

Здесь описывается, как экспортировать функции и как использовать свой собственный основной. Обратите внимание, где говорится "какой-то другой язык, скажем С." Он говорит об этом, потому что вы можете сделать это с любого языка (и компилятора), который может вызывать функции ваниль C, которые вы экспортируете, и что HsFFI.h обеспечивает. Это язык агностик, а компилятор агностик. Все, что требуется, - это возможность вызова функций C с использованием стандартных соглашений о вызовах в вашей системе, которые, безусловно, предоставляет компилятор С++ (например, g++).

Ответ 5

В cabal 2.0 добавлена функция "посторонних библиотек", которая, похоже, решает проблемы компоновщика, а также делает процесс сборки в целом более приятным.

Я собрал небольшой пример учебника https://github.com/pdlla/haskell-ffi-cabal-foreign-library-examples