Интерфейс внешней функции - Foreign function interface

А интерфейс внешней функции (FFI) - это механизм, с помощью которого программа, написанная на одном язык программирования может вызывать подпрограммы или использовать службы, написанные на другом языке.

Именование

Термин взят из спецификации для Common Lisp, который явно относится к языковым функциям для межъязыковых вызовов как таковым;[1] этот термин также официально используется Haskell[2] и Python языки программирования.[3] В других языках используется другая терминология: Язык программирования Ада Переговоры о "языковые привязки ", пока Ява именует свой FFI как JNI (Собственный интерфейс Java ) или JNA (Собственный доступ Java ). Интерфейс внешних функций стал общей терминологией для механизмов, которые предоставляют такие услуги.

Операция

Основная функция интерфейса внешней функции состоит в том, чтобы сопоставлять семантику и соглашения о вызовах одного языка программирования ( хозяин язык, или язык, который определяет FFI), с семантикой и соглашениями другого ( гость язык). Этот процесс также должен учитывать среды выполнения и / или двоичные интерфейсы приложений обоих. Сделать это можно несколькими способами:

  • Требование, чтобы функции гостевого языка, которые должны быть вызываемыми на языке хоста, были указаны или реализованы определенным образом; часто используют какую-либо библиотеку совместимости.
  • Использование инструмента для автоматического "оборачивания" функций на гостевом языке соответствующими клей код, который выполняет любой необходимый перевод.
  • Использование библиотеки-оболочки
  • Ограничение набора возможностей основного языка, которые могут использоваться в разных языках. Например, функции C ++, вызываемые из C, могут (как правило) не включать ссылочные параметры или вызывать исключения.

ИФИ могут быть осложнены следующими соображениями:

  • Если один язык поддерживает вывоз мусора (GC), а другой нет; Следует позаботиться о том, чтобы код языка, отличного от GC, не сделал ничего, чтобы вызвать сбой GC в другом. В JNI, например, код C, который «удерживает» ссылки на объекты, которые он получает от Java, должен «зарегистрировать» этот факт с помощью Среда выполнения Java (JRE); в противном случае Java может удалить объекты до того, как C завершит работу с ними. (Код C также должен явно освободить свою ссылку на любой такой объект, если C больше не нуждается в этом объекте.)
  • Сложные или нетривиальные объекты или типы данных может быть трудно сопоставить из одной среды в другую.
  • Для обоих языков может оказаться невозможным поддерживать ссылки на один и тот же экземпляр изменяемого объекта из-за проблемы сопоставления, описанной выше.
  • Один или оба языка могут работать на виртуальная машина (ВМ); более того, если и то, и другое, вероятно, это будут разные виртуальные машины.
  • Кросс-язык наследование и другие различия, например, между системы типов или между объектно-композиционные модели, может быть особенно сложно.

По языку

Примеры FFI включают:

  • Ада языковые привязки, позволяющие не только вызывать сторонние функции, но также экспортировать свои функции и методы для вызова из кода, отличного от Ada.[4]
  • C ++ имеет тривиальный FFI с C, поскольку языки имеют значительное общее подмножество. Первичный эффект внешний "C" объявление в C ++ - отключить C ++ искажение имени.
  • Чистый обеспечивает двунаправленный FFI со всеми следующими языками C или stdcall соглашение о вызовах.[5][6]
  • CNI, альтернатива JNI, используемая в среде компилятора GNU.
  • D делает это так же, как C ++ делает, с внешний "C" через extern (C ++)
  • Дротик включает дротик: ffi[7] библиотека для вызова родной C код для мобильных, командной строки и серверных приложений
  • Динамические языки, Такие как Python, Perl, Tcl, и Рубин все они обеспечивают легкий доступ к машинному коду, написанному на C / C ++ (или на любом другом языке, подчиняющемся соглашениям о вызовах C / C ++).
  • Фактор имеет FFI для C, Фортран, Цель-C, и Windows COM; все они позволяют динамически импортировать и вызывать произвольные разделяемые библиотеки.
  • ИФИ Common Lisp и Haskell
  • Фортран В 2003 есть модуль ISO_C_BINDING, который предоставляет взаимодействующие типы данных (как внутренние типы, так и структуры POD), совместимые указатели, совместимые глобальные хранилища данных и механизмы для вызова C из Fortran и для вызова Fortran из C.[8]
  • Идти может вызывать код C напрямую через "C" псевдо-пакет.[9]
  • GWT, в котором Java скомпилирован в JavaScript, имеет FFI, называемый JSNI, который позволяет исходному тексту Java вызывать произвольные функции JavaScript, а для JavaScript - выполнять обратный вызов в Java.
  • JNI, который обеспечивает интерфейс между Ява и C / C ++, предпочтительные системные языки в большинстве систем, в которых развернута Java. JNA предоставляет интерфейс с собственными библиотеками без необходимости писать клей код. Другой пример JNR
  • Юля имеет позвонить ключевое слово для вызова C (и других языков, например Fortran);[10] в то время как пакеты, предоставляющие аналогичную поддержку без шаблонов, доступны для некоторых языков, например для Python[11] (например, для обеспечения поддержки OO и GC), Java (и поддерживает другие языки JDK, такие как Scala) и R. Интерактивное использование с C ++ также возможно с пакетом Cxx.jl.
  • PHP предоставляет FFI C.[12]
  • Python предоставляет ctypes и cffi модули. Например, модуль ctypes может загружать функции C из общие библиотеки /DLL «на лету» и автоматически переводить простые типы данных между семантикой Python и C следующим образом:
    импорт ctypeslibc = ctypes.CDLL('/lib/libc.so.6')  # Под Linux / Unixт = libc.время(Никто)                   # Эквивалентный код C: t = время (NULL)Распечатать(т)
  • P / Invoke, который обеспечивает интерфейс между Microsoft общеязыковая среда выполнения и собственный код.
  • Ракетка имеет собственный FFI, в значительной степени основанный на макросах, который позволяет динамически импортировать произвольные общие библиотеки.[13][14]
  • Раку может позвонить Рубин, Python, Perl, Brainfuck, Lua, C, C ++, Идти и схема Хитрость /Гамбит [15] [16]
  • Ржавчина также определяет интерфейс внешней функции.[17]
  • Visual Basic имеет декларативный синтаксис, который позволяет ему вызывать функции не-Unicode C.
  • Одна из основ Компонентная объектная модель - это общий формат интерфейса, который изначально использует те же типы, что и Visual Basic для строк и массивов.
  • LuaJIT, а вовремя реализация Lua, имеет FFI, который позволяет «вызывать внешние функции C и использовать структуры данных C из чистого кода Lua».[18]
  • 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 и других языков.

Кроме того, многие FFI могут быть созданы автоматически: например, SWIG. Однако в случае язык расширения может произойти семантическая инверсия отношений гостя и хоста, когда меньшая часть языка расширения - это гость, вызывающая службы в большей части языка хоста, например, написание небольшого плагина [19] для GIMP.[20]

Некоторые ИФИ могут работать как самостоятельные функции, в то время как другие также позволяют вызывать функции, встроенные в объект или класс (часто называемые вызовы методов ); некоторые даже позволяют переносить сложные типы данных и / или объекты через языковые границы.

В большинстве случаев FFI определяется языком «более высокого уровня», поэтому он может использовать службы, определенные и реализованные на языке более низкого уровня, обычно системном языке, таком как C или же C ++. Обычно это делается либо для доступа к службам ОС на языке, на котором определен API ОС, либо из соображений производительности.

Многие FFI также предоставляют вызываемому языку средства для вызова служб на основном языке.

Термин "интерфейс внешней функции" обычно не используется для описания многоязычной среды выполнения, такой как Microsoft общеязыковая среда выполнения, где предоставляется общая «подложка», которая позволяет любому CLR-совместимому языку использовать службы, определенные в любом другом. (Однако в этом случае CLR действительно включает FFI, P / Invoke, для вызова вне среды выполнения.) Кроме того, многие архитектуры распределенных вычислений, такие как Вызов удаленного метода Java (RMI), RPC, CORBA, МЫЛО и D-автобус позволять писать разные услуги на разных языках; такие архитектуры обычно не считаются FFI.

Особые случаи

Есть несколько особых случаев, когда языки компилируются в одну виртуальную машину с байт-кодом, например Clojure и Ява, а также Эликсир и Erlang. Поскольку интерфейса нет, это не FFI, строго говоря, хотя он предлагает те же функции пользователю.

Смотрите также

Рекомендации

  1. ^ «Руководство пользователя CFFI». common-lisp.org. Получено 2015-06-18.
  2. ^ «Введение в FFI». HaskellWiki. Получено 19 июн 2015. FFI в Haskell используется для вызова функций из других языков (на данный момент в основном C), а для C - для вызова функций Haskell.
  3. ^ «Документация CFFI». Получено 19 июн 2015. Интерфейс внешних функций C для Python. Цель состоит в том, чтобы предоставить удобный и надежный способ вызова скомпилированного кода C из Python с использованием объявлений интерфейса, написанных на C.
  4. ^ «Интерфейс с другими языками». Adaic.org. Получено 2013-09-29.
  5. ^ «Зарубежный экспорт». Получено 2020-05-25.
  6. ^ "Вызов C с чистого листа". Получено 2018-04-25.
  7. ^ "dart: ffi library". Получено 2020-01-01.
  8. ^ "'fortran-iso-c-binding 'тег вики ". Переполнение стека.
  9. ^ "cgo - язык программирования Go". Получено 2015-08-23.
  10. ^ "Вызов кода C и Fortran · Язык Julia". docs.julialang.org. Получено 2018-02-11.
  11. ^ PyCall.jl: пакет для вызова функций Python из языка Julia, JuliaPy, 08.02.2018, получено 2018-02-11
  12. ^ «PHP: FFI - Руководство». Группа PHP. Получено 13 июн 2019.
  13. ^ Эли Барзилай. "Внешний интерфейс Racket". Docs.racket-lang.org. Получено 2013-09-29.
  14. ^ "TR600.pdf" (PDF). Получено 2013-09-29.
  15. ^ «Встроенные реализации». Получено 2017-08-15.
  16. ^ «Родной зов». Получено 2017-08-15.
  17. ^ «Использование внешних функций для вызова внешнего кода». Получено 2019-06-01.
  18. ^ Майк Полл. «Библиотека FFI». Luajit.org. Получено 2013-09-29.
  19. ^ «4. Пример сценария». Gimp.org. 2001-02-04. Получено 2013-09-29.
  20. ^ «Script-Fu и плагины для GIMP». Gimp.org. Получено 2013-09-29.

внешняя ссылка