GHCi linker error with FFI-imported MPI constants (via c2hs)

116 Views Asked by At

I'm figuring out how haskell-mpi works by rewriting the binding. I'm trying to re-use the MPICH installation that was set up by installing PETSc (which is working fine). Question: make main gives me a correct module in GHCi, but when I request to compute commWorld, the linker complains that it can't find the MPI_COMM_WORLD symbol (which however is in scope of the makefile).

What am I doing wrong? Thanks in advance

error:

ByteCodeLink: can't find label
During interactive linking, GHCi couldn't find the following symbol:
   MPI_COMM_WORLD

Main.chs :

type MPIComm = {# type MPI_Comm #} 
newtype Comm = MkComm { fromComm :: MPIComm } deriving (Eq, Show)
foreign import ccall "&MPI_COMM_WORLD" commWorld_ :: Ptr MPIComm
foreign import ccall "&MPI_COMM_SELF" commSelf_ :: Ptr MPIComm

commWorld, commSelf :: Comm
commWorld = MkComm <$> unsafePerformIO $ peek commWorld_
commSelf = MkComm <$> unsafePerformIO $ peek commSelf_

makefile:

PETSC_DIR_ARCH = ${PETSC_DIR}/arch-darwin-c-debug
PETSC_DIR_ARCH_INCLUDE = ${PETSC_DIR_ARCH}/include

main : 
    c2hs Main.chs -C -I${PETSC_DIR_ARCH}/include -C -I${PETSC_DIR}/include 
    ghci Main.hs -L${PETSC_DIR_ARCH}/lib -lpetsc -lmpich

mpi.h

 typedef int MPI_Comm;
 #define MPI_COMM_WORLD ((MPI_Comm)0x44000000)
 #define MPI_COMM_SELF  ((MPI_Comm)0x44000001)
2

There are 2 best solutions below

4
Reid Barton On BEST ANSWER
foreign import ccall "&MPI_COMM_WORLD" commWorld_ :: Ptr MPIComm

means that commWorld_ will be a pointer to the variable MPI_COMM_WORLD. But in fact MPI_COMM_WORLD is not a variable, it's a CPP macro, so it's not the kind of thing that has an address at all, and this is what the linker error is telling you.

I would probably add a C file with a definition like

const MPI_Comm hs_MPI_COMM_WORLD = MPI_COMM_WORLD;

and import that in the way that you have done. Perhaps c2hs has some magic that will do this for you.

0
Reid Barton On

I just learned that the CApiFFI extension (since GHC 7.6) allows you to import not only C-level "functions" that may actually be macros, but also C-level values that may actually be macros. So you should be able to write

{-# LANGUAGE CApiFFI #-}

type MPIComm = {# type MPI_Comm #} 
foreign import capi "mpi.h value MPI_COMM_WORLD" :: MPIComm

without having to write an additional C file (GHC will do it for you).

See the documentation at https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ffi.html#ffi-capi.