gpt4 book ai didi

haskell - Haskell 中 PETSc FFI 的库设计

转载 作者:行者123 更新时间:2023-12-02 16:42:41 28 4
gpt4 key购买 nike

我想制作PETSc(的子集) Haskell 通过 FFI 接口(interface)提供库,以便对用户隐藏内存和错误管理;

  • 使用如下所示的命令构建带有共享库的 PETSc 3.5.3,测试套件运行成功
  • 准备了 .hsc 文件#2,其中包含 header 导入、类型和两个示异常(exception)部函数接口(interface)
  • 准备了 Makefile #3 来自动化构建; make test1 通过并使用加载的模块启动 GHCi。

由于该库在 MPI 和完全分布式数据结构支持的并行操作上表现出色,因此在大多数操作期间,不应期望 Haskell 产生大量数据流量(所有数据组装、计算和释放都应由库原语完成),但是仅在“数据就绪”时。 PETSc 相关的 Haskell 函数大多在 IO monad 中具有值,因为我们无法保证纯度(例如,返回的 C 错误代码可能由于程序外部的原因而有所不同)

    需要
  • unsafePerformIO来包装内存分配和错误管理。这个思路正确吗?坏主意
  • 用 GHC 编译的二进制文件可以用 mpirun 执行吗? 是的

我对所有建议和评论持开放态度。预先感谢您

--注释:我们希望 GHC 生成一个 mpirun 可以执行的二进制文件:因为可以使用 -optl 标志将选项从 GHC 命令行传递到链接器(引用 here ) ,有人建议我使用诸如 ghc -optl-static -lmpich 之类的组合。一旦我可以尝试,我会添加更多相关内容。

1)配置命令:

$ ./configure --with-cc=gcc --with-cxx=g++ --with-fc=gfortran --with-shared-libraries=1 --download-mpich --download-fblaslapack

2) PETSC.hsc

{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}
module PETSc where

import Foreign
import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String

#include <petscksp.h>
#include <petscsys.h>

newtype PetscErrCode = PetscErrCode {unPetscErrCode :: CInt} deriving (Eq, Show)
newtype PetscInt = PetscInt {unPetscInt :: CInt} deriving (Eq, Show)

data Petsc
-- PetscErrorCode PetscInitialize(int *argc,char ***args,const char file[],const char help[])
foreign import ccall unsafe "petscsys.h PetscInitialize"
c_petscInitialize :: Ptr CInt -> Ptr (Ptr CString) -> CString -> CString -> IO PetscErrCode

-- PetscErrorCode PetscFinalize(void)
foreign import ccall unsafe "petscsys.h PetscFinalize"
c_petscFinalize :: IO PetscErrCode

3) 生成文件

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

PETSc.hs:
hsc2hs PETSc.hsc -I ${PETSC_DIR}/include -I ${PETSC_DIR_ARCH}/include

test1: PETSc.hs
ghci -dynamic PETSc.hs -L${PETSC_DIR_ARCH}/lib

最佳答案

雄心勃勃!我很想使用 C2HS 而不是 hsc2hs,因为它可以为您生成一些国外进口的样板。 (我是 C2HS 的维护者,所以你可以对我所说的持保留态度!)

例如,您可以像这样绑定(bind) PetscInitializePetscFinalize:

-- This is in PETSc.chs
module PETSc (initialize, finalize) where

import Foreign
import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String
import System.Environment (getArgs)

#include <petscksp.h>
#include <petscsys.h>

-- Marshalling helpers for PETSc error codes.

newtype ErrCode = ErrCode { unErrCode :: Int }
deriving (Eq, Show)

convErrCode :: CInt -> ErrCode
convErrCode = ErrCode . fromIntegral

{#typedef PetscErrorCode CInt#}
{#default out `ErrCode' [PetscErrorCode] convErrCode#}


-- Marshalling helpers for "char ***" argument to PetscInitialize.

withCStrings :: [String] -> ([CString] -> IO a) -> IO a
withCStrings ss f = case ss of
[] -> f []
(s:ss') -> withCString s $ \cs -> do
withCStrings ss' $ \css -> f (cs:css)

withCStringArray :: [String] -> (Ptr CString -> IO a) -> IO a
withCStringArray ss f = withCStrings ss $ \css -> withArray css f

withCStringArrayPtr :: [String] -> (Ptr (Ptr CString) -> IO a) -> IO a
withCStringArrayPtr ss f = withCStringArray ss $ \css -> with css f


-- Low-level function hooks.

{#fun PetscInitialize as internal_initialize
{`Int', withCStringArrayPtr* `[String]', `String', `String'}
-> `ErrCode'#}
{#fun PetscFinalize as finalize {} -> `ErrCode'#}


-- Better API for initialization.

initialize :: String -> String -> IO ErrCode
initialize file help = do
args <- getArgs
internal_initialize (length args) args file help

这对于 C2HS 来说实际上是一个非常困难的例子,因为管理 char *** 参数到 PetscInitialize 的编码有点尴尬,但是你得到了主意。大多数其他编码情况应该更加简单——处理指针和数组非常容易,编码 C 字符串也是如此。 (如果您决定使用它,我很乐意帮助解决 C2HS 问题。)

一旦你有了这个,你就可以这样调用它:

-- This is Tst.hs or something...
module Main where

import PETSc

main :: IO ()
main = do
res1 <- initialize "" ""
print res1
res2 <- finalize
print res2

还不是很有用,但这是一个开始!像这样编译:

c2hs -C -I/opt/petsc/arch-linux2-cxx-opt/include PETSc.chs
ghc --make Tst.hs PETSc.hs -L/opt/petsc/arch-linux2-cxx-opt/lib/ -lpetsc

(根据需要调整路径,obvs)。

回答您的其他问题:

  • 不要使用 unsafePerformIO ,除非您确实确定您所调用的函数是“有效纯净的” - PetscInitialize 当然不会满足该条件。如果您不想直接将所有内容都包含在 IO monad 中,您可以编写一个 PETSc monad 作为 IO 的一种受限包装器,但您在 PETSc 方面所做的大部分工作实际上都在 IO monad 中,因为您将通过调用 API 函数来设置内部 PETSc 状态位,并且您需要捕获该状态Haskell 函数类型的有效性。

  • 使用 mpirun 运行 GHC 生成的二进制文件应该不成问题。

我也不会编写 makefile。您应该能够使用 Cabal 轻松完成这一切!

关于haskell - Haskell 中 PETSc FFI 的库设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29324155/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com