Могу ли я экспортировать функции в Racket после вызова другой функции? - PullRequest
1 голос
/ 27 мая 2010

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

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

Ответы [ 3 ]

2 голосов
/ 28 мая 2010

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

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

0 голосов
/ 23 августа 2014

CMake может автоматически найти libpython путь:

find_package( PythonLibs 3.3 REQUIRED )

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

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

0 голосов
/ 28 мая 2010

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

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