Ответ 1
Джон Л. предложил расширение CApiFFI
, которое делает именно то, что я хочу: позволяет импортировать значения, а не местоположения. Сейчас:
{-# LANGUAGE CApiFFI #-}
newtype {-# CTYPE "foo.h" "struct foo_struct" #-} Foo = Foo { getFoo :: (Ptr Foo) }
foreign import capi "foo.h value FOO_GEORGE" fooGeorgePtr :: Ptr a
fooGeorge = Foo fooGeorgePtr
Другим преимуществом является то, что это работает независимо от того, является ли FOO_GEORGE
переменной C или макросом препроцессора. C API Im, работающий с использованием как двух, так и разных реализаций одного и того же API, с которым я ссылаюсь, делает это по-другому, поэтому он не зависит от этого.
Тем не менее, theres камнем преткновения: CApiFFI
не работает с ghci! Проблема известна, и она не будет исправлена до GHC 8.0.1 (когда я впервые написал это, она должна была появиться 7.10, и затем был продвинут вперед). У меня очень хакерское решение. CApiFFI
работает, создавая библиотеку C "на лету", компилируя и связывая программу Haskell с ней. Он удаляет библиотеку по завершении; проблема ghci, кажется, в том, что файл .so ушел к тому моменту, когда ghci нужно связать с ним. Я просто хватаю файл .c во время компиляции, прежде чем он удаляется, затем скомпилируйте его и скажите ghci, чтобы загрузить его. Поскольку я не очень часто меняю эту часть программы, она работает для меня достаточно хорошо.
Мой метод для ловли временного файла .c - запустить ghci в Emacs compilation-mode
, с (setq compilation-auto-jump-to-first-error t)
. Emacs видит ошибку и загружает файл .c в буфер до того, как GHC доберутся до его удаления - к тому времени, как я вижу, файл пропал, но Ive получил содержимое в буфере.
Обновление: ghci -fobject-code Foo
работает, но может видеть только имена, экспортированные из модуля.