2

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)
ocramz
  • 816
  • 6
  • 18

2 Answers2

3
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.

Reid Barton
  • 14,951
  • 3
  • 39
  • 49
  • I'm thinking of the {# enum ... #} macro. However the definition above is taken from the original binding library. However I am not certain because I can't get `haskell-mpi` to build properly yet. Thank you for now – ocramz May 06 '15 at 16:35
  • 1
    `haskell-mpi` does the same as what I suggested, see the file `src/cbits/constants.c`. – Reid Barton May 06 '15 at 16:47
  • `src/cbits/constants.c` begins : #define MPI_CONST(ty, name, defn) ty name = defn; MPI_CONST (MPI_Datatype, mpi_char, MPI_CHAR) MPI_CONST (MPI_Datatype, mpi_wchar, MPI_WCHAR) ... The #define is a function macro and all the next lines are..concrete types? – ocramz May 06 '15 at 18:29
  • 1
    There's also a {#const ...#} thing in C2HS, but it only really works in cases where what's on the right hand side of #define expands to something that looks like a constant in Haskell as well as in C (so "#define ABC 123" and "{#const ABC#}" works fine). In this case, doing "{#const MPI_COMM_WORLD#}" splices the C code "(MPI_Comm) (void *) &ompi_mpi_comm_world" into your Haskell code, which is no use at all! I think Reid's suggestion is definitely the way to go here. – Ian Ross May 15 '15 at 12:03
1

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.

Reid Barton
  • 14,951
  • 3
  • 39
  • 49