Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use C library from Haskell?

I am trying to call a C function from Haskell using the FFI and I keep getting this error :

ghc.exe: ^^ Could not load 'getSize', dependency unresolved. See top entry above.

main: ByteCodeLink: can't find label During interactive linking, GHCi couldn't find the following symbol: getSize This may be due to you not asking GHCi to load extra object files, archives or DLLs needed by your current session. Restart GHCi, specifying the missing library using the -L/path/to/object/dir and -lmissinglibname flags, or simply by naming the relevant files on the GHCi command line. Alternatively, this link failure might indicate a bug in GHCi. If you suspect the latter, please send a bug report to:
[email protected]

I am using the stdio.h library in my C library:

C library

// lib.h
#include <stdio.h>

double getSize() {
    double size = 0;
    scanf("$f", &size);
    return size;
}

FFI module

{-# LANGUAGE ForeignFunctionInterface #-}
module Ffi where

import Foreign
import Foreign.C.Types

foreign import ccall "lib.h getSize" c_size :: IO Double

Main

module Main where
import Ffi

main :: IO ()
main = do a <- getLine
          b <- c_size
          print $ "got from C: " ++ show b

Running script

gcc -o lib -lib.h
runghc main

P.S. Could this be because I somehow have to specify the dependency stdio.h somewhere else too?

like image 466
Bercovici Adrian Avatar asked Mar 03 '23 21:03

Bercovici Adrian


1 Answers

Okay, there are several things to do here:

  • Rename "lib.h" to "lib.c". It's a C source file (containing code), not a C header file.
  • Ideally, add a separate "lib.h" header file with the prototype for getSize.
  • Fix the bug in "lib.c". You want "%lf" in place of "$f" to read in a double.
  • Compile the program with ghc instead of running it with runghc. A single ghc command can compile and link both Haskell modules and C code.

In other words, your files should look like:

// lib.c
#include "lib.h"
#include <stdio.h>
double getSize() {
    double size = 0;
    scanf("%lf", &size);
    return size;
}
// lib.h
double getSize(void);
-- Ffi.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Ffi where
import Foreign
import Foreign.C.Types
foreign import ccall "lib.h getSize" c_size :: IO Double
-- Main.hs
module Main where
import Ffi
main :: IO ()
main = do a <- getLine
          b <- c_size
          print $ "got from C: " ++ show b

and you should compile it with:

$ ghc Main.hs lib.c
[1 of 2] Compiling Ffi              ( Ffi.hs, Ffi.o )
[2 of 2] Compiling Main             ( Main.hs, Main.o )
Linking Main ...

Then you can run it, supply a line for the Haskell getLine and a second line for the C scanf, and it should work fine:

$ ./Main
hello world!!   -- line for Haskell
135.0           -- line for C
"got from C: 135.0"
like image 116
K. A. Buhr Avatar answered Mar 15 '23 13:03

K. A. Buhr