В Ракетке я могу экспортировать функции после того, как другая функция была вызвана?

Я пытаюсь создать привязку к libpython использование FFI схемы. Чтобы сделать это, я должен получить местоположение 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 (созданный Python ссылки) глобально так или иначе. Там какой-либо путь состоит в том, чтобы экспортировать эти функции, после того как Python ссылки называют? Другими словами, я хотел бы, чтобы кто-то использующий модуль смог сделать это:

(require pyscheme)
(link-python)
(Py_Initialize)

... или это:

(require pyscheme)
(link-python "/weird/location/for/libpython.so")
(Py_Initialize)

... но имейте, это дает ошибку:

(require pyscheme)
(Py_Initialize)

Как я могу сделать это?

1
задан Yasir Arsanukaev 12 February 2011 в 12:30
поделиться

2 ответа

Вероятно, самый простой способ сделать что-то подобное - отложить привязку до тех пор, пока они не понадобятся. Примерно так (непроверенный) код:

#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"))

Если вы можете выполнить настройку внутри самой функции, вы не будете связывать функции, которые никогда не вызываются:

#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 с python , и IIRC, решение проблем с памятью было неприятным. (Но это было до того, как у нас была действующая иностранная система.)

2
ответ дан 3 September 2019 в 00:15
поделиться

Я сделал не так много модулей, но думаю, вам нужно «предоставить» функции, которые вы хотите загрузить в новое пространство имен.

(module pyscheme scheme
  (provide
   link-python
   Py_Initialize
   <...>)
  (require foreign)
  (unsafe!)

  (define (link-python [lib "/usr/lib/libpython2.6.so"])
    (ffi-lib lib)))
(require pyscheme)
(link-python "/weird/location/for/libpython.so")
(Py_Initialize)
0
ответ дан 3 September 2019 в 00:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: