这是我第一次尝试使用Racket的FFI。我想创建一个绑定到libgit2
的应用程序,以便操作GIT存储库。
我需要做的第一件事是初始化存储库as shown in the libgit2
documentation:
git_repository *repo = NULL;
int error = git_repository_init(&repo, "/tmp/…", false);
在Racket中获取函数调用非常简单:
(require ffi/unsafe
ffi/unsafe/define)
(define-ffi-definer define-libgit (ffi-lib "/opt/local/lib/libgit2.dylib"))
(define _git_repository-ptr (_cpointer/null 'git_repository))
(define-libgit git_repository_init (_fun _git_repository-ptr _string _bool -> _int))
但是然后尝试使用该功能不起作用:
-> (define new_repo _git_repository-ptr)
-> (git_repository_init new_repo "/tmp/..." #f)
; git_repository->C: argument is not `git_repository' pointer
; argument: #<ctype>
; [,bt for context]
libgit2
不提供初始化指针的函数as shown in the Racket FFI documentation example。
这是定义可空指针并将其初始化为NULL
的正确方法吗?
git_repository
是库中定义的struct
。我是否应该在Racket端使用define-cstruct
来正确使用它?这可能很麻烦,因为struct
是根据其他struct
来定义的,具有一定程度的嵌套。有没有处理这种情况的模式?
答案 0 :(得分:7)
问题不在于指针未初始化为null;事实上,git_repository_init
文档并没有说它必须初始化为任何东西。问题是它是一个out参数,而你的函数声明没有指定。
这是我测试的一些代码(在Ubuntu 14.04上),对我有用:
> (require ffi/unsafe ffi/unsafe/define)
> (define-ffi-definer define-libgit (ffi-lib "libgit2"))
> (define _git_repository-ptr (_cpointer/null 'git_repository))
> (define-libgit git_repository_init (_fun (repo : (_ptr o _git_repository-ptr)) _string _bool -> (rc : _int) -> (values repo rc)))
> (git_repository_init "/tmp/repo" #f)
#<cpointer:git_repository>
0
有关如何指定out参数的信息,请参阅_ptr
的文档。 (您也可以使用它来指定输入/输出参数,但这些通常很少见。)
(当然,你最终会想按摩你的FFI,而不是像我的例子中那样返回两个值,而是简单地检查错误的返回代码,并在适当时引发适当的Racket错误,以及如果成功则返回存储库指针。)