我正在尝试使用方案的 FFI 创建到 libpython 的绑定(bind)。为此,我必须获取 python 的位置,创建 ffi-lib
,然后从中创建函数。所以例如我可以这样做:
(module pyscheme scheme
(require foreign)
(unsafe!)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(ffi-lib lib))
一切都很好,但我想不出导出函数的方法。例如,我可以这样做:
(define Py_Initialize (get-ffi-obj "Py_Initialize" libpython (_fun -> _void)))
...但是我必须以某种方式全局存储对 libpython(由 link-python 创建)的引用。调用 link-python 后,有什么方法可以导出这些函数吗?换句话说,我希望使用该模块的人能够做到这一点:
(require pyscheme)
(link-python)
(Py_Initialize)
...或者这个:
(require pyscheme)
(link-python "/weird/location/for/libpython.so")
(Py_Initialize)
...但是有这个给出一个错误:
(require pyscheme)
(Py_Initialize)
我该怎么做?
最佳答案
执行此类操作的最简单方法可能是延迟绑定(bind),直到需要它们为止。像这样的(未经测试的)代码:
#lang scheme
(require scheme/foreign)
(unsafe!)
(define libpython #f)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(if libpython
(error "Foo!")
(begin (set! libpython (ffi-lib lib))
(set! Py_Initialize
(get-ffi-obj "Py_Initialize" libpython
(_fun -> _void))))))
(define (Py_Initialize . args)
(error 'Py_Initialize "python not linked yet"))
您可以在函数内部进行设置,这样您就不会绑定(bind)从未调用过的函数:
#lang scheme
(require scheme/foreign)
(unsafe!)
(define libpython #f)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(if libpython (error "Foo!") (set! libpython (ffi-lib lib))))
(define (Py_Initialize . args)
(if libpython
(begin (set! Py_Initialize
(get-ffi-obj "Py_Initialize" libpython
(_fun -> _void)))
(apply Py_Initialize args))
(error 'Py_Initialize "python not linked yet")))
并且由于您不想对每个函数都执行此操作,因此您应该将其包装在一个宏中:
#lang scheme
(require scheme/foreign)
(unsafe!)
(define libpython #f)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(if libpython (error "Foo!") (set! libpython (ffi-lib lib))))
(define-syntax-rule (defpython <name> type)
(define (<name> . args)
(if libpython
(begin (set! <name> (get-ffi-obj '<name> libpython <type>))
(apply <name> args))
(error '<name> "python not linked yet"))))
(defpython Py_Initialize (_fun -> _void))
(defpython Py_Foo (_fun _int _int -> _whatever))
...more...
但有两个高级注释:
尽管有可能,但以这种方式拖延事情似乎很丑陋。我宁愿使用一些在代码开始时已知的环境变量。
过去曾尝试链接 plt scheme to python和 IIRC,处理内存问题并不愉快。 (但这是在我们拥有当前的外国系统之前。)
关于c - 在 Racket 中,我可以在调用另一个函数后导出函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2923909/