-
ForeignFunctionInterface -
- С момента:
-
6.8.1
- Статус:
-
Включено в
GHC2024,GHC2021,Haskell2010
Разрешить использование интерфейса внешних функций Haskell.
GHC (в основном) соответствует спецификации Haskell Foreign Function Interface, указанной в Haskell Report. Для получения более подробной информации обратитесь к соответствующей главе Haskell Report.
Поддержка FFI включена по умолчанию, но её можно включить или выключить явно с помощью флага ForeignFunctionInterface.
GHC реализует ряд расширений, специфичных для GHC, к главе FFI в Haskell 2010 Report. Эти расширения описаны в Расширения GHC для главы FFI, но обратите внимание, что программы, использующие эти функции, не являются переносимыми. Поэтому эти функции следует избегать, где это возможно.
Документация библиотек FFI приведена в сопроводительной документации библиотеки; см., например, модуль Foreign.
6.17.1. Отличия GHC от главы FFI
6.17.1.1. Гарантированная безопасность вызовов
В Haskell 2010 Report указано, что safe вызовы FFI должны позволять внешним вызовам безопасно вызывать код Haskell. На практике это означает, что вызываемые функции также должны предполагать, что значения Haskell, размещенные в куче, могут перемещаться произвольно, чтобы разрешить работу сборщика мусора.
Это существенно ограничивает авторов библиотек, поскольку подразумевает, что передавать любые ссылки на объекты, размещенные в куче, внешней функции safe небезопасно. Например, часто желательно передавать непривязанные ByteArray# напрямую в нативный код, чтобы избежать в противном случае ненужного копирования. Однако это нельзя безопасно делать для вызовов safe , поскольку массив может быть перемещен сборщиком мусора в середине вызова.
В главе разрешено перемещать объекты во время вызовов unsafe . Таким образом, строго соответствующие Haskell 2010 программы также не могут передавать ссылки на объекты, размещенные в куче, вызовам unsafe FFI.
GHC, начиная с версии 8.4, гарантирует, что сборка мусора никогда не произойдет во время вызова unsafe, даже в интерпретаторе байткода, и гарантирует, что вызовы unsafe будут выполнены в потоке вызова. Это делает безопасным передачу объектов, размещенных в куче, небезопасным функциям.
В предыдущих версиях GHC использовал предоставляемую главой свободу, выполняя safe вызовы внешних функций вместо unsafe вызовов в интерпретаторе байткода. Это означало, что некоторые пакеты, работающие при компиляции, терпят неудачу в GHCi (например, #13730). Но в последних версиях этого уже нет.
6.17.1.2. Взаимодействие между вызовами safe и привязанными потоками
Вызов safe , вызывающий Haskell, выполняется в привязанном потоке RTS. Это означает, что любая вложенность вызовов safe будет выполняться в том же операционной системе потоке. Однако последовательные вызовы safe не имеют этой привилегии и могут выполняться в произвольных потоках ОС.
Это поведение считается деталью реализации, и код, зависящий от состояния локального потока, должен вместо этого использовать один из интерфейсов, предоставленных в Control.Concurrent, чтобы сделать это явным.
Дополнительную информацию о том, что такое привязанные потоки, см. в документации для Control.Concurrent.
Дополнительные сведения об реализации см. в документе: “Расширение интерфейса внешних функций Haskell с помощью одновременности”. Последний доступный по адресу здесь.
6.17.1.3. Varargs не поддерживаются соглашением о вызове ccall
Обратите внимание, что функции, требующие аргументов varargs, не поддерживаются соглашением о вызове ccall. Внешние импорты, которым необходимо вызвать такие функции, должны использовать соглашение capi, предоставляя явную сигнатуру для требуемого шаблона вызова. Например, можно написать:
foreign import "capi" "printf"
my_printf :: Ptr CChar -> CInt -> IO ()
printInt :: CInt -> IO ()
printInt n = my_printf "printed number %d" n