2016-03-15 3 views
3

Я пытаюсь вызвать функцию C от Haskell с использованием c2hs.Как вызвать функцию C, которая использует обратный вызов в Haskell?

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() 

Я не понимаю, что часть недостающей Ptr или FunPtr здесь , Я также попытался обернуть все 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

Ничего себе, действительно! Я даже не заметил, что это было! Большое спасибо! –