If one has a constant value in a C/C++ header file that one wants to bring into a Haskell project:
static const char * Name = "Name_001";
How does one do so using Haskell's FFI functionality?
If one has a constant value in a C/C++ header file that one wants to bring into a Haskell project:
static const char * Name = "Name_001";
How does one do so using Haskell's FFI functionality?
As @melpomene points out, static
variables cannot be used for FFI. Every translation unit that includes this header file will create its own non-exported copy of the static variable. Unsurprisingly, that means that Name
won't even be present in a compiled object file.
$ cat c_file.c
static const char * Name = "Name_001";
$ gcc -O -c c_file.c
$ objdump c_file.o
c_file.o: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
$
Compare this to a non-static Name
variable:
$ cat c_file.c
const char * Name = "Name_001";
$ gcc -O -c c_file.c
$ objdump c_file.o
c_file.o: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000010 g __DATA,__data _Name
$
It goes without saying that you need Name
to be in the symbol table to be imported in Haskell's FFI. Taking the second variant, importing Name
becomes pretty easy:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.Storable
import Foreign.C.String
import Foreign.Ptr
foreign import ccall "&Name" c_Name :: Ptr CString
name :: IO String
name = peek c_Name >>= peekCString
main :: IO ()
main = do
n <- name
putStrLn ("Name: " ++ n)
If you want to convince me that Name
is actually a constant string, you probably need char const * const = "Name_001;
. Then, feel free to toss an unsafeDupablePerformIO
in the definition of name
:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.Storable
import Foreign.C.String
import Foreign.Ptr
import System.IO.Unsafe
foreign import ccall "&Name" c_Name :: Ptr CString
name :: String
name = unsafeDupablePerformIO (peek c_Name >>= peekCString)
main :: IO ()
main = putStrLn ("Name: " ++ name)
In either case, you get the expected output:
$ gcc -O -c c_file.c
$ ghc -O2 -Wall main.hs c_file.o
[1 of 1] Compiling Main ( main.hs, main.o )
Linking main ...
$ ./main
Name: Name_001