Внешняя функция интерфейс ( FFI ) представляет собой механизм , с помощью которого программа , написанная на одном языке программирования может вызывать процедуры или использовать грим услуг , написанные на другом.
Именование
Этот термин происходит из спецификации Common Lisp , которая явно относится к языковым функциям для межъязыковых вызовов как таковых; [1] этот термин также официально используется в языках программирования Haskell , [2] Rust , [3] и Python . [4] В других языках используется другая терминология: язык программирования Ada говорит о « языковых привязках », в то время как Java ссылается на свой FFI как на JNI ( Java Native Interface ) или JNA ( Java Native Access ). Интерфейс внешних функций стал общей терминологией для механизмов, которые предоставляют такие услуги.
Операция
Основная функция интерфейса внешней функции состоит в том, чтобы согласовать семантику и соглашения о вызовах одного языка программирования ( основной язык или язык, определяющий FFI) с семантикой и соглашениями другого ( гостевого языка). Этот процесс также должен учитывать среду выполнения и / или двоичные интерфейсы приложений обоих. Сделать это можно несколькими способами:
- Требование, чтобы функции гостевого языка, которые должны быть вызваны на языке хоста, были указаны или реализованы определенным образом, часто с использованием какой-либо библиотеки совместимости.
- Использование инструмента для автоматического «оборачивания» функций на гостевом языке с помощью соответствующего связующего кода , который выполняет любой необходимый перевод.
- Использование библиотек-оболочек
- Ограничение набора возможностей основного языка, которые могут использоваться в разных языках. Например, функции C ++, вызываемые из C, могут (как правило) не включать ссылочные параметры или вызывать исключения.
ИФИ могут быть осложнены следующими соображениями:
- Если один язык поддерживает сборку мусора (GC), а другой - нет; Следует позаботиться о том, чтобы код языка, отличного от GC, не сделал ничего, чтобы вызвать сбой GC в другом. В JNI, например, код C, который «удерживает» ссылки на объекты, которые он получает от Java, должен «зарегистрировать» этот факт в среде выполнения Java (JRE); в противном случае Java может удалить объекты до того, как C завершит их работу. (Код C также должен явно освободить свою ссылку на любой такой объект, если C больше не нуждается в этом объекте.)
- Сложные или нетривиальные объекты или типы данных может быть трудно сопоставить из одной среды в другую.
- Для обоих языков может оказаться невозможным поддерживать ссылки на один и тот же экземпляр изменяемого объекта из-за проблемы сопоставления, описанной выше.
- На виртуальной машине (ВМ) могут работать один или оба языка ; более того, если и то, и другое, вероятно, это будут разные виртуальные машины.
- Межъязыковое наследование и другие различия, такие как между системами типов или между моделями композиции объектов , могут быть особенно трудными.
По языку
Примеры ИФИ:
- Привязки языка Ada , позволяющие не только вызывать внешние функции, но также экспортировать его функции и методы для вызова из кода, отличного от Ada. [5]
- C ++ имеет тривиальный FFI с C , поскольку языки имеют значительное общее подмножество. Основным эффектом объявления extern «C» в C ++ является отключение искажения имени C ++ .
- Clean обеспечивает двунаправленный FFI для всех языков, следующих за C или соглашением о вызовах stdcall . [6] [7]
- CNI , альтернатива JNI, используемая в среде компилятора GNU.
- D делает это так же, как C ++ , с extern "C" через extern (C ++)
- Dart включает библиотеку dart: ffi [8] для вызова собственного кода C для мобильных, командной строки и серверных приложений.
- Динамические языки , такие как Python , Perl , Tcl и Ruby , обеспечивают легкий доступ к машинному коду, написанному на C / C ++ (или на любом другом языке, подчиняющемся соглашениям о вызовах C / C ++).
- Factor имеет FFI для C, Fortran , Objective-C и Windows COM ; все они позволяют динамически импортировать и вызывать произвольные разделяемые библиотеки.
- FFI Common Lisp и Haskell
- В Fortran 2003 есть модуль ISO_C_BINDING, который обеспечивает совместимые типы данных (как внутренние типы, так и структуры POD), совместимые указатели, совместимые глобальные хранилища данных и механизмы для вызова C из Fortran и для вызова Fortran из C. [9]
- Go может вызывать код C напрямую через
"C"
псевдопакет. [10] - GWT , в котором Java скомпилирован в JavaScript, имеет FFI, называемый JSNI, который позволяет исходному тексту Java вызывать произвольные функции JavaScript, а JavaScript - выполнять обратный вызов в Java.
- JNI , который обеспечивает интерфейс между Java и C / C ++, предпочтительными системными языками в большинстве систем, где развернута Java. JNA предоставляет интерфейс с собственными библиотеками без написания связующего кода . Другой пример - JNR
- У Nim есть FFI, который позволяет ему использовать исходный код из C , C ++ и Objective-C . Он также может взаимодействовать с Javascript.
- У Джулии есть
ccall
ключевое слово для вызова C (и других языков, например Fortran); [11] в то время как пакеты, обеспечивающие аналогичную поддержку без шаблонов, доступны для некоторых языков, например для Python [12] (например, для обеспечения поддержки OO и GC), Java (и поддерживает другие языки JDK, такие как Scala) и R • Интерактивное использование с C ++ также возможно с пакетом Cxx.jl. - PHP предоставляет FFI для C. [13]
- Рубин обеспечивает FFI либо через FFI драгоценный камень, или через стандартную библиотеку скрипку .
требовать 'скрипку'libm = Fiddle . dlopen ( '/lib/libm.so.6' )# Эквивалентно: двойной пол (двойной x); floor = Fiddle :: Function . new ( libm . sym ( 'floor' ), # ptr - это ссылочная функция (или символ) Fiddle :: Handle. [ Fiddle :: TYPE_DOUBLE ] , # args - это массив аргументов, переданный в функцию ptr . Fiddle :: TYPE_DOUBLE # ret_type - тип возвращаемого значения функции )# Эквивалентно: floor (3.14159); этаж . называть ( 3 . 14159 ) # => 3.0
- Python предоставляет ctypes и cffi модули. Например, модуль ctypes может загружать функции C из общих библиотек / DLL на лету и автоматически переводить простые типы данных между семантикой Python и C следующим образом:
import ctypes libc = ctypes . CDLL ( '/lib/libc.so.6' ) # В Linux / Unix t = libc . time ( None ) # Эквивалентный код C: t = time (NULL) print ( t )
- P / Invoke , который обеспечивает интерфейс между средой выполнения Microsoft Common Language Runtime и собственным кодом.
- Racket имеет собственный FFI, в значительной степени основанный на макросах, который позволяет динамически импортировать произвольные общие библиотеки. [14] [15]
- Raku может вызывать Ruby , Python , Perl , Brainfuck , Lua , C , C ++ , Go и Scheme Guile / Gambit [16] [17]
- Rust также определяет интерфейс внешней функции. [18]
- Visual Basic имеет декларативный синтаксис, который позволяет ему вызывать функции C, отличные от Unicode.
- Одна из основ компонентной объектной модели - это общий формат интерфейса, который изначально использует те же типы, что и Visual Basic для строк и массивов.
- LuaJIT, своевременная реализация Lua , имеет FFI, который позволяет «вызывать внешние функции C и использовать структуры данных C из чистого кода Lua». [19]
- PhoneGap (назывался Apache Callback, но теперь Apache Cordova) - это платформа для создания собственных мобильных приложений с использованием HTML, CSS и JavaScript. Дополнительно имеет FFI через функции обратного вызова JavaScript для доступа к методам и свойствам встроенных функций мобильного телефона, включая акселерометр, камеру (также PhotoLibrary и SavedPhotoAlbum), компас, хранилище (база данных SQL и локальное хранилище), уведомление, мультимедиа и захват (воспроизведение и запись или аудио и видео), файл, контакты (адресная книга), события, информация об устройстве и подключении. [1] , [2] .
- Wolfram Language предоставляет технологию под названием WSTP (Wolfram Symbolic Transfer Protocol), которая обеспечивает двунаправленный вызов кода между другими языками с привязками для C ++, Java, .NET и других языков.
- Zig предоставляет FFI для c с помощью встроенной
cImport
функции. [20]
Кроме того, многие FFI могут быть сгенерированы автоматически: например, SWIG . Однако в случае языка расширения может произойти семантическая инверсия отношений гостя и хоста, когда меньшая часть языка расширения - это гость, вызывающая службы в большей части языка хоста, например, написание небольшого плагина [21 ] для GIMP. [22]
Некоторые FFI ограничены автономными функциями , в то время как другие также разрешают вызовы функций, встроенных в объект или класс (часто называемые вызовами методов ); некоторые даже позволяют переносить сложные типы данных и / или объекты через языковые границы.
В большинстве случаев FFI определяется языком «более высокого уровня», поэтому он может использовать службы, определенные и реализованные на языке более низкого уровня, обычно системном языке, таком как C или C ++ . Обычно это делается либо для доступа к службам ОС на языке, на котором определен API ОС, либо из соображений производительности.
Многие FFI также предоставляют вызываемому языку средства для вызова служб на основном языке.
Термин «интерфейс внешней функции» обычно не используется для описания многоязычных сред выполнения, таких как Microsoft Common Language Runtime , где предоставляется общий «субстрат», который позволяет любому CLR-совместимому языку использовать службы, определенные в любом другом. (Однако в этом случае CLR действительно включает FFI, P / Invoke для вызова вне среды выполнения.) Кроме того, многие архитектуры распределенных вычислений, такие как удаленный вызов метода Java (RMI), RPC, CORBA , SOAP и D- Автобус позволяет писать разные услуги на разных языках; такие архитектуры обычно не считаются FFI.
Особые случаи
Есть некоторые особые случаи, когда языки компилируются в одну и ту же виртуальную машину с байт-кодом, например, Clojure и Java , а также Elixir и Erlang . Поскольку интерфейса нет, это, строго говоря, не FFI, хотя он предлагает пользователю те же функции.
Смотрите также
- Языковая совместимость
- Язык определения интерфейса
- Соглашение о вызове
- Изменение имени
- Интерфейс прикладного программирования
- Бинарный интерфейс приложения
- Сравнение виртуальных машин приложений
- SWIG
- Удаленный вызов процедур
- libffi
Рекомендации
- ^ "Руководство пользователя CFFI" . common-lisp.org . Проверено 18 июня 2015 .
- ^ «Введение в FFI» . HaskellWiki . Дата обращения 19 июня 2015 .
FFI в Haskell используется для вызова функций из других языков (в основном C на данный момент), а для C - для вызова функций Haskell.
- ^ "std :: ffi - Ржавчина" . Проверено 1 апреля 2021 года .
Этот модуль предоставляет утилиты для обработки данных через интерфейсы, отличные от Rust, такие как другие языки программирования и базовая операционная система. Он в основном используется для привязок FFI (интерфейса внешних функций) и кода, который должен обмениваться C-подобными строками с другими языками.
- ^ «Документация CFFI» . Дата обращения 19 июня 2015 .
Интерфейс внешних функций C для Python. Цель состоит в том, чтобы предоставить удобный и надежный способ вызова скомпилированного кода C из Python с использованием объявлений интерфейса, написанных на C.
- ^ «Интерфейс с другими языками» . Adaic.org . Проверено 29 сентября 2013 .
- ^ «Зарубежный экспорт» . Проверено 25 мая 2020 .
- ^ «Вызов C с чистого листа» . Проверено 25 апреля 2018 .
- ^ "dart: ffi library" . Проверено 1 января 2020 .
- ^ " Вики-теги ' fortran-iso-c-binding'" . Переполнение стека .
- ^ «cgo - язык программирования Go» . Проверено 23 августа 2015 .
- ^ "Вызов кода C и Fortran · Язык Julia" . docs.julialang.org . Проверено 11 февраля 2018 .
- ^ PyCall.jl: пакет для вызова функций Python из языка Julia , JuliaPy, 08.02.2018 , получено 11.02.2018
- ^ «PHP: FFI - Руководство» . Группа PHP . Проверено 13 июня 2019 .
- ^ Эли Барзилай. «Ракетный внешний интерфейс» . Docs.racket-lang.org . Проверено 29 сентября 2013 .
- ^ «TR600.pdf» (PDF) . Проверено 29 сентября 2013 .
- ^ «Встроенные реализации» . Проверено 15 августа 2017 .
- ^ «Родной зов» . Проверено 15 августа 2017 .
- ^ «Использование внешних функций для вызова внешнего кода» . Проверено 1 июня 2019 .
- ^ Майк Полл. «Библиотека FFI» . Luajit.org . Проверено 29 сентября 2013 .
- ^ «Импорт из файла заголовка C» . Zig Software Foundation . Проверено 11 марта 2021 .
- ^ «4. Пример сценария» . Gimp.org. 2001-02-04 . Проверено 29 сентября 2013 .
- ^ «Скрипт-фу и плагины для GIMP» . Gimp.org . Проверено 29 сентября 2013 .
Внешние ссылки
- c2.com: интерфейс внешней функции
- Интерфейс внешних функций Haskell 98
- Аллегро Common Lisp FFI
- Генератор интерфейса посторонних функций для occam-pi
- UFFI: Универсальный интерфейс внешних функций Lisp
- CFFI: Общий интерфейс внешних функций для Common Lisp
- Собственный интерфейс Java: Руководство и спецификация программиста
- Спецификация JNI
- JSNI (собственный интерфейс JavaScript)
- библиотека dyncall, использующая ядра вызовов ассемблера для различных процессоров, ОС и соглашений о вызовах
- FFCALL
- C / Invoke
- libffi