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

StackOverflow https://stackoverflow.com/questions/2923909

  •  05-10-2019
  •  | 
  •  

Вопрос

Я пытаюсь создать привязку к 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 (созданный 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)

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

Это было полезно?

Решение

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

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

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

#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...

Но два нота Handlevel:

  • Несмотря на то, что это возможно, кажется уродливым задержать вещи таким образом. Я предпочел бы использовать некоторую переменную среды, которая известна, когда код начинается.

  • Была попытка в прошлом ссылаться Схема PLT в Python, И IIRC, занимаясь вопросами памяти не понравилась. (Но это прежде, чем у нас была текущая внешняя система на месте.)

Другие советы

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

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

Cmake может автоматически найти libpython дорожка:

find_package( PythonLibs 3.3 REQUIRED )

Более подробный пример здесь.

Тогда вы можете использовать некоторые связанные Sherd lib. Например:https://github.com/niitsuma/pyjsonrpcembd

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top