Domanda

Attualmente sto scrivendo un app in C ++ e ha scoperto che alcune delle sue funzionalità sarebbe meglio scritto in Haskell. Ho visto le istruzioni su chiamando Haskell dal codice C , ma è possibile fare lo stesso con C ++?

EDIT:. Per chiarire, quello che sto cercando è un modo per compilare il codice Haskell in una libreria esterna che g ++ può collegarsi con il codice oggetto da C ++

UPDATE:. Ho messo un esempio di lavoro sotto per chiunque altro interessato (anche in modo non dimenticherò)

È stato utile?

Soluzione

Modifica si dovrebbe vedere anche la risposta di Tomer di seguito. La mia risposta qui descrive la teoria di quello che sta succedendo, ma ho può avere alcuni dei dettagli di esecuzione incompleta, mentre la sua risposta è un esempio di lavoro completo.

Come SCLV indica, la compilazione dovrebbe essere un problema. La difficoltà non è probabile che sia collegando il codice C ++, e qui si avrà un po 'di difficoltà a ottenere tutte le librerie di runtime necessari collegate. Il problema è che i programmi Haskell devono essere collegati con le librerie di runtime Haskell, e C ++ programmi devono essere collegati con le librerie di runtime C ++. Nella pagina Wiki si fa riferimento, quando lo fanno

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

per compilare il programma C, che in realtà fa due passaggi: Compila il programma C in un file oggetto, e poi lo lega insieme. Scritto fuori, che sarebbe qualcosa di simile (probabilmente non del tutto giusto, come io non parlo GHC):

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

GHC solo agisce come GCC (e, IIUC, funzionalmente è GCC) durante la compilazione del programma C. Durante il collegamento, però, è diverso da quello che succede se si chiama direttamente GCC, perché comprende anche magicamente le librerie di runtime Haskell. G ++ funziona allo stesso modo per i programmi C ++ -. Quando viene usato come un linker, include le librerie di runtime C ++

Quindi, come ho già detto, è necessario compilare in modo che i collegamenti con entrambe le librerie di runtime. Se si esegue G ++ in verbose modalità per compilare e collegare un programma, in questo modo:

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

si creerà una lunga lista di uscita su ciò che sta facendo; alla fine sarà una linea di output in cui si fa il collegamento (con il sottoprogramma collect2) che indica quali librerie si collega a. È possibile confrontare che per l'uscita per la compilazione di un semplice programma C per vedere cosa c'è di diverso per C ++; sul mio sistema, aggiunge -lstdc++.

In questo modo, si dovrebbe essere in grado di compilare e collegare il programma misto Haskell / C ++ in questo modo:

$ 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

, perché hai specificato -lstdc++, includerà la libreria di runtime C ++ (supponendo -l è la sintassi GHC destra, ne avrete bisogno di controllare), e perché hai collegato con ghc, includerà Haskell libreria di runtime. Questo dovrebbe portare a un programma di lavoro.

In alternativa, si dovrebbe essere in grado di fare qualcosa di simile alle indagini uscita -v con GHC, e capire cosa libreria Haskell runtime (o librerie) si collega a per il supporto Haskell, e quindi aggiungere quella biblioteca durante il collegamento del programma con C ++ , proprio come si fa già per i programmi C ++ puro. (Risposta di See Tomer per i dettagli di quella, dato che è quello che ha fatto.)

Altri suggerimenti

Per chiunque fosse interessato, questo è il caso di test che ho finalmente ottenuto lavorando:


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;
}

Ho fatto le compilazioni e collega sulla mia macchina Windows. I comandi da eseguire (in questo ordine) sono:

>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

La lunga lista di parametri per l'ultimo g ++ comando è l'esecuzione

>ghc M.hs -v

e poi copiare il comando in cui si dice "*** Linker:". (Alcuni dei primi parametri devono essere rimossi)


Il risultato:

>test
hello
22

Questo è un tutorial sul tema:

https://github.com/jarrett/cpphs

Si copre chiamando Haskell da C ++ e chiamando C da Haskell.

Dal momento che è possibile chiamare Haskell da C, non c'è ragione per cui non si può chiamare da C ++. Chiamata C ++ da Haskell, d'altra parte, è molto più difficile e di solito richiede un wrapper C.

Modifica per espandere. Le istruzioni sono sbagliato incompleti. Sono una pagina wiki. Guardare direttamente il manuale di GHC: http: // www.haskell.org/ghc/docs/6.12.2/html/users_guide/ffi-ghc.html

Questo viene descritto come esportare le funzioni, e come utilizzare il proprio principale. Nota in cui si dice "qualche altra lingua, dicono C." Dice questo perché si può fare questo da qualsiasi lingua (e compilatore) in grado di richiamare le funzioni di vaniglia C che si esporta, e che fornisce HsFFI.h. Questo è agnostico lingua e compilatore agnostico. Tutto ciò che richiede è la capacità di richiamare le funzioni C utilizzando le convenzioni di chiamata standard, sul sistema, che un compilatore C ++ (come g ++) fornisce certamente.

cabala 2.0 aggiunto la funzione "estero-library", che sembra risolvere i problemi di linker oltre a rendere l'intero processo di costruzione molto più piacevole in generale.

Ho messo insieme un breve esempio un'esercitazione https: // GitHub. com / PDLLA / Haskell-FFI-cabala-stranieri-library-esempi

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top