2016-03-15 70 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

哇,的確!我甚至沒有注意到它在那裏!非常感謝你! –

相關問題