For a proof-of-concept, I want to link some trivial Haskell code into my Visual C++ application (using Visual Studio 2013). Building with GHC 7.8.3 32-bit works, but building with GHC 7.8.4 64-bit does not (notice the slight discrepancy in GHC version too).
There are 3 files: Grep.hs
and StartEnd.c
are built with GHC to form a DLL. main.cpp
is built with Visual Studio 2013 and attempts to link in the DLL library.
I am building the DLL from this:
> ghc -shared -O -optc-O -o Grep.dll StartEnd.c Grep.hs
And from within Visual Studio, I simply link against Grep.dll.a
and include C:\Program Files\MinGHC-7.8.4\ghc-7.8.4\lib\include
, but linking fails with
1>main.obj : error LNK2001: unresolved external symbol _HsEnd
1>main.obj : error LNK2001: unresolved external symbol _freegrep
1>main.obj : error LNK2001: unresolved external symbol _grep
1>main.obj : error LNK2001: unresolved external symbol _HsStart
1>C:\Code\Grep\dist\Win32\Release\Grep.exe : fatal error LNK1120: 4 unresolved externals
The exact same process works when I build with 32-bit, but not 64-bit. What could I be doing wrong? (I am building a 64-bit app when attempting to link the 64-bit library.)
Source files:
Grep.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Grep where
import Foreign
import Foreign.C.String
import Data.List (isInfixOf)
filterlines f = unlines . filter f . lines
grep :: CString -> CString -> IO CString
grep i s = do
ii <- peekCString i
ss <- peekCString s
newCString $ (filterlines (isInfixOf ii)) ss
freegrep :: CString -> IO ()
freegrep s = free s
foreign export ccall grep :: CString -> CString -> IO CString
foreign export ccall freegrep :: CString -> IO ()
StartEnd.c
#include <Rts.h>
void HsStart()
{
int argc = 1;
char* argv[] = {"ghcDll", NULL}; // argv must end with NULL
// Initialize Haskell runtime
char** args = argv;
hs_init(&argc, &args);
}
void HsEnd()
{
hs_exit();
}
main.cpp
#include <HsFFI.h>
#include <Grep_stub.h>
#include <iostream>
extern "C" {
void HsStart();
void HsEnd();
}
int main(int argc, char* argv[])
{
HsStart();
HsPtr str;
str = grep("test", "This is a test\nwith many lines\nand it failed\nand the test passed");
if (str)
{
std::cout << (char*) str;
freegrep(str);
}
HsEnd();
return 0;
}