2016-03-15 109 views
3

我正在尝试使用c2hsHaskell调用以下C函数。如何调用在Haskell中使用回调的C函数?

void rd_kafka_conf_set_rebalance_cb (
    rd_kafka_conf_t *conf, 
    void (*rebalance_cb) (rd_kafka_t *rk, 
          rd_kafka_resp_err_t err, 
          rd_kafka_topic_partition_list_t *partitions, 
          void *opaque)); 

我不熟悉c2hs,并且在声明绑定时遇到麻烦。

这是我已经试过:

--callback type 
type RebalanceCbFun = 
    Ptr RdKafkaT -> CInt -> Ptr RdKafkaTopicPartitionListT -> Ptr Word8 -> IO() 

foreign import ccall safe "wrapper" 
    mkRebalanceCallback :: RebalanceCbFun -> IO (FunPtr RebalanceCbFun) 

foreign import ccall unsafe "rd_kafka.h &rd_kafka_conf_set_rebalance_cb" 
    rdKafkaConfSetRebalanceCb :: Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO() 

不过,我有以下错误而编译此代码:

Unacceptable type in foreign declaration: 
    ‘Ptr RdKafkaConfT 
    -> FunPtr 
     (Ptr RdKafkaT 
     -> Int32 -> Ptr RdKafkaTopicPartitionListT -> Ptr Word8 -> IO()) 
    -> IO()’ cannot be marshalled in a foreign call 
    A foreign-imported address (via &foo) must have type (Ptr a) or (FunPtr a) 
When checking declaration: 
    foreign import ccall unsafe "static rd_kafka.h &rd_kafka_conf_set_rebalance_cb" rdKafkaConfSetRebalanceCb 
    :: Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO() 

我不明白是什么部分缺失PtrFunPtr这里。 我也试过整个rdKafkaConfSetRebalanceCb包装成FunPtr,如:

foreign import ccall unsafe "rd_kafka.h &rd_kafka_conf_set_rebalance_cb" 
    rdKafkaConfSetRebalanceCb :: FunPtr (Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO()) 

不知道它是有道理的,尽管它编译... 但我不知道如何使用这个功能,这就是我尝试(这是我想在结束了签名):

kafkaConfSetRebalanceCb :: RdKafkaConfTPtr -> RebalanceCbFun -> IO() 
kafkaConfSetRebalanceCb conf cb = do 
    cb' <- mkRebalanceCallback cb 
    withForeignPtr conf $ \c -> rdKafkaConfSetRebalanceCb c cb' 
    return() 

现在抱怨我没有要调用的函数,只是一个指针的函数(因为FunPtr的包装)。

你能告诉我如何C绑定可以正确完成上面的C签名?

+0

未来访问者注意:C函数将会像这样调用Haskell代码,不能导入'unsafe'。 –

回答

3

以下文件适合我(与ghc -c Test.hs)编译。唯一真正的区别是我在国外进口中省略了&

{-# LANGUAGE ForeignFunctionInterface #-} 
module Test where 
import Data.Word 
import Foreign.C.Types 
import Foreign.Ptr 
import Foreign.ForeignPtr 

newtype RdKafkaT = RdKafkaT (Ptr RdKafkaT) 
newtype RdKafkaConfT = RdKafkaConfT (Ptr RdKafkaConfT) 
newtype RdKafkaTopicPartitionListT = RdKafkaTopicPartitionListT (Ptr RdKafkaTopicPartitionListT) 

type RebalanceCbFun = 
    Ptr RdKafkaT -> CInt -> Ptr RdKafkaTopicPartitionListT -> Ptr Word8 -> IO() 

foreign import ccall safe "wrapper" 
    mkRebalanceCallback :: RebalanceCbFun -> IO (FunPtr RebalanceCbFun) 

foreign import ccall unsafe "rd_kafka.h rd_kafka_conf_set_rebalance_cb" 
    rdKafkaConfSetRebalanceCb :: Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO() 

kafkaConfSetRebalanceCb :: ForeignPtr RdKafkaConfT -> RebalanceCbFun -> IO() 
kafkaConfSetRebalanceCb conf cb = do 
    cb' <- mkRebalanceCallback cb 
    withForeignPtr conf $ \c -> rdKafkaConfSetRebalanceCb c cb' 
+0

哇,的确!我甚至没有注意到它在那里!非常感谢你! –