我使用bindings-DSL来帮助处理FFI声明中的一些样板。但是我发现自己声明了一组相关的函数,这些函数只有几个文本元素不同,而我真的宁愿用宏来声明它们。 CPP或CPPHS似乎是理想的选择,但我无法在Haskell的上下文中找到它的使用示例。
我已经根据我对C宏的了解将其放入了我期望的工作中:
#define declare_vector_funcs (t, tn, ct) \
#opaque_t vector_##t \
#ccall create_std_vector##tn , IO (Ptr <vector_##t##>) \
#ccall carray_to_std_vector##tn , Ptr ct -> CSize -> IO (Ptr <vector_##t##>) \
#ccall std_vector##tn##_to_carray , Ptr <vector_##t##> -> IO (Ptr ct) \
#ccall std_vector##tn##_length , Ptr <vector_##t##> -> IO CSize
基本上,我希望在扩展此宏时定义外部(不透明)类型和4个外部函数。但是,这不起作用,因为它将参数列表后面的所有内容读作GHC编译指示,并且失败。
我已经尝试了几次不同的迭代,例如弄乱间距并将所有内容放在一行(用括号括起来区分不同的宏调用)。
我该如何解决这个问题呢?放弃绑定的答案-DSL使用有利于直接翻译,这很好,但我绝对不想手动写出所有这些。
我也非常感谢这种CPP使用的一些例子。
这是我删除宏名称和参数列表之间的空格时得到的错误消息:
CPP.hsc:13:39: error: '#' is not followed by a macro parameter
compiling dist/build/Foreign/CPP_hsc_make.c failed (exit code 1)
command was: /usr/bin/g++ -c dist/build/Foreign/CPP_hsc_make.c -o dist/build/Foreign/CPP_hsc_make.o -fno-stack-protector -D__GLASGOW_HASKELL__=708 -Dlinux_BUILD_OS=1 -Dx86_64_BUILD_ARCH=1 -Dlinux_HOST_OS=1 -Dx86_64_HOST_ARCH=1 -Iinclude/ -fpermissive -std=c++11 -fPIC -Idist/build/autogen -include dist/build/autogen/cabal_macros.h -I/usr/local/lib/x86_64-linux-ghc-7.8.2/bindings-DSL-1.0.21/include -I/usr/lib/ghc-7.8.2/base-4.7.0.0/include -I/usr/lib/ghc-7.8.2/integer-gmp-0.5.1.0/include -I/usr/lib/ghc-7.8.2/include -I/usr/lib/ghc-7.8.2/include/
有了空格,我收到了更长的错误信息:
dist/build/Foreign/CPP.hs:1:16:
unknown flag in {-# OPTIONS_GHC #-} pragma: tn,
dist/build/Foreign/CPP.hs:1:16:
unknown flag in {-# OPTIONS_GHC #-} pragma: ct)
dist/build/Foreign/CPP.hs:1:16:
unknown flag in {-# OPTIONS_GHC #-} pragma: #opaque_t
dist/build/Foreign/CPP.hs:1:16:
unknown flag in {-# OPTIONS_GHC #-} pragma: vector_##t
对于每个令牌都会继续。我相当肯定这只是意味着不应该包括空间,但我不确定发生了什么。
编辑:
我交换了方法,我试图直接生成最终的外国进口。宏(我将在一秒内粘贴)通过预处理器发出一些警告,但实际上尝试使用宏还没有工作:
#define declare_vector_funcs(t, tn ,ct) \
data C'vector_##t = C'vector_##t \
foreign import ccall "create_std_vector##tn" c'create_std_vector##tn :: IO (Ptr C'vector_##t) \
foreign import ccall "carray_to_std_vector##tn" c'carray_to_std_vector##tn :: Ptr ct -> CSize -> IO (Ptr vector_##t) \
foreign import ccall "std_vector##tn##_to_carray" c'std_vector##tn##_to_carray :: Ptr vector_##t -> IO (Ptr ct) \
foreign import ccall "std_vector##tn##_length" c'std_vector :: Ptr vector_##t -> IO CSize
在使用网站上,我尝试使用它:
#declare_vector_funcs int , i , CInt
匹配C侧的等效声明。我希望它生成一个看起来像这样的块:
data C'vector_int = C'vector_int
foreign import ccall "create_std_vectori" c'create_std_vectori :: IO (Ptr C'vector_int)
foreign import ccall "carray_to_std_vectori" c'carray_to_std_vectori :: Ptr CInt -> CSize -> IO (Ptr vector_int)
foreign import ccall "std_vectori_to_carray" c'std_vectori_to_carray :: Ptr vector_int -> IO (Ptr CInt)
foreign import ccall "std_vectori_length" c'std_vector :: Ptr vector_int -> IO CSize
但我得到一个错误:
CPP.hsc: In function ‘int main(int, char**)’:
CPP.hsc:22:31: error: expected primary-expression before ‘int’
CPP.hsc:22:37: error: ‘i’ was not declared in this scope
CPP.hsc:22:41: error: ‘CInt’ was not declared in this scope
CPP.hsc:22:45: error: ‘hsc_declare_vector_funcs’ was not declared in this scope
CPP.hsc:23:31: error: expected primary-expression before ‘float’
CPP.hsc:23:39: error: ‘f’ was not declared in this scope
CPP.hsc:23:43: error: ‘CFloat’ was not declared in this scope
CPP.hsc:24:31: error: expected primary-expression before ‘double’
CPP.hsc:24:40: error: ‘d’ was not declared in this scope
CPP.hsc:24:44: error: ‘CDouble’ was not declared in this scope
所以我显然需要将import Foreign.C
添加到顶部,但即便如此,还有更深层次的问题 - 我无法将这些令牌视为无意义,就像我想要的那样有些东西试图解释它们。有人有什么想法吗?
答案 0 :(得分:4)
您尝试做的事情是不可能的,我不会想到,当您在hsc
文件中定义宏时,它会被内联到您生成的.hs
文件,如果该宏调用.hsc
宏..那些已经不再可用的了。你能做的最好:
module Test where
import Foreign.Ptr
import Foreign.C.Types
data T
data Tn
data Ct
#opaque_t vector_T
#ccall create_std_vectorTn , IO (Ptr <vector_T>)
#ccall carray_to_std_vectorTn , Ptr Ct -> CSize -> IO (Ptr <vector_T>)
#ccall std_vectorTn_to_carray , Ptr <vector_T> -> IO (Ptr Ct)
#ccall std_vectorTn_length , Ptr <vector_T> -> IO CSize
如果您的C编译器知道在哪里找到bindings.dsl.h
,那么您应该将它包含在顶部;我并没有用hsc2hs --include=<path-to-bindings.dsl.h> test.hsc
编译。这将生成以下文件:
{-# LINE 1 "test.hsc" #-}
module Test where
{-# LINE 2 "test.hsc" #-}
import Foreign.Ptr
import Foreign.C.Types
data T
data Tn
data Ct
data C'vector_T = C'vector_T
{-# LINE 11 "test.hsc" #-}
foreign import ccall "create_std_vectorTn" c'create_std_vectorTn
:: IO (Ptr C'vector_T)
foreign import ccall "&create_std_vectorTn" p'create_std_vectorTn
:: FunPtr (IO (Ptr C'vector_T))
{-# LINE 12 "test.hsc" #-}
foreign import ccall "carray_to_std_vectorTn" c'carray_to_std_vectorTn
:: Ptr Ct -> CSize -> IO (Ptr C'vector_T)
foreign import ccall "&carray_to_std_vectorTn" p'carray_to_std_vectorTn
:: FunPtr (Ptr Ct -> CSize -> IO (Ptr C'vector_T))
{-# LINE 13 "test.hsc" #-}
foreign import ccall "std_vectorTn_to_carray" c'std_vectorTn_to_carray
:: Ptr C'vector_T -> IO (Ptr Ct)
foreign import ccall "&std_vectorTn_to_carray" p'std_vectorTn_to_carray
:: FunPtr (Ptr C'vector_T -> IO (Ptr Ct))
{-# LINE 14 "test.hsc" #-}
foreign import ccall "std_vectorTn_length" c'std_vectorTn_length
:: Ptr C'vector_T -> IO CSize
foreign import ccall "&std_vectorTn_length" p'std_vectorTn_length
:: FunPtr (Ptr C'vector_T -> IO CSize)
{-# LINE 15 "test.hsc" #-}
所以看起来像定义自己的宏是要走的路:
mymacro.h
#define hsc_declare_vector_funcs(t,tn,ct)\
hsc_opaque_t(vector_##t)\
hsc_ccall(create_std_vector##tn ,IO (Ptr <vector_##t>))\
hsc_ccall(carray_to_std_vector##tn , Ptr ct -> CSize -> IO (Ptr <vector_##t>)) \
hsc_ccall(std_vector##tn##_to_carray , Ptr <vector_##t> -> IO (Ptr ct)) \
hsc_ccall(std_vector##tn##_length , Ptr <vector_##t> -> IO CSize)
test.hsc
module Test where
#include "mymacro.h"
import Foreign.Ptr
import Foreign.C.Types
#declare_vector_funcs int, i, CInt
test.hs
module Test where
import Foreign.Ptr
import Foreign.C.Types
data C'vector_int = C'vector_int
foreign import ccall "create_std_vectori" c'create_std_vectori
:: IO (Ptr C'vector_int)
foreign import ccall "&create_std_vectori" p'create_std_vectori
:: FunPtr (IO (Ptr C'vector_int))
foreign import ccall "carray_to_std_vectori" c'carray_to_std_vectori
:: Ptr CInt -> CSize -> IO (Ptr C'vector_int)
foreign import ccall "&carray_to_std_vectori" p'carray_to_std_vectori
:: FunPtr (Ptr CInt -> CSize -> IO (Ptr C'vector_int))
foreign import ccall "std_vectori_to_carray" c'std_vectori_to_carray
:: Ptr C'vector_int -> IO (Ptr CInt)
foreign import ccall "&std_vectori_to_carray" p'std_vectori_to_carray
:: FunPtr (Ptr C'vector_int -> IO (Ptr CInt))
foreign import ccall "std_vectori_length" c'std_vectori_length
:: Ptr C'vector_int -> IO CSize
foreign import ccall "&std_vectori_length" p'std_vectori_length
:: FunPtr (Ptr C'vector_int -> IO CSize)
答案 1 :(得分:2)
以下示例编译:
{-# LANGUAGE CPP #-}
#define MYMACRO 3
#define MAX(a,b) (if ((a) < (b)) \
then (b) \
else (a))
main = print $ show (MAX(MYMACRO,4) :: Int)
我需要代码宏周围的parens,以便以下(也)工作:
main = print $ show MAX(MYMACRO,4)
答案 2 :(得分:0)
如果你想使用bindings-DSL做到这一点,请看看它是如何在bindings-gobject中完成的。您必须使用hsc_ *宏。