Как код, написанный на одном языке, вызывается с другого языка

Это вопрос, который я всегда хотел знать ответ, но никогда не спрашивала.

Как код, написанный одним языком, особенно интерпретируемым языком, вызывается кодом, написанным скомпилированным языком.

например, скажем, я пишу игру на C++, и я передаю на аутсорсинг некоторые из поведения AI, которые будут написаны в схеме. Как код, написанный в схеме, попадает в точку, которая может использоваться скомпилированным кодом C++? Как он используется источником C++ код, и как он используется скомпилированным кодом C++? Есть ли разница в том, как он используется?

по теме

как взаимодействуют несколько языков в одном проекте?

7 ответов


нет однозначного ответа на вопрос, который работает везде. В общем, ответ заключается в том, что два языка должны договориться о "чем-то" - наборе или правилах или "протоколе вызова".

на высоком уровне любой протокол должен указывать три вещи:

  • "discovery": как найти друг о друге.
  • "linking": как сделать соединение (после того, как они знают друг о друге).
  • "Invocation": как на самом деле делать запросы к каждому другой.

детали сильно зависят от самого протокола.

иногда два языка сговариваются работать вместе. Иногда эти два языка соглашаются поддерживать какой-то внешний протокол. В эти дни часто задействована ОС или "среда выполнения" (.NET и Java). Иногда способность идет только одним путем ("а "может вызвать" В", но" в "не может вызвать"а").

обратите внимание, что это та же проблема, с которой сталкивается любой язык, когда связь с ОС. Ядро Linux не написано в схеме, вы знаете!

давайте посмотрим некоторые типичные ответы из мира Windows:

  • C С C++: C++ использует искаженную ("искаженную") вариацию"протокола C". C++ может вызывать C, А C может вызывать C++ (хотя имена иногда могут быть довольно беспорядочными, и может потребоваться внешняя помощь в переводе имен). Это не просто Windows; это обычно верно для всех платформ это поддерживает обоих. Большинство популярных ОС также используют "протокол C".

  • VB6 против большинства языков: предпочтительным методом VB6 является "com-протокол". Другие языки должны иметь возможность писать COM-объекты для использования с VB6. VB6 также может создавать COM-объекты (хотя и не все возможные варианты COM-объектов).

    VB6 также может говорить о очень ограниченном варианте "протокола C", а затем только совершать вызовы снаружи: он не может создавать объекты, которые могут разговаривайте непосредственно через "протокол C".

  • языки .NET: все языки .NET связывают компиляцию с одним и тем же языком низкого уровня (IL). Среда выполнения управляет связью, и с этой точки зрения все они выглядят как один и тот же язык.

  • VBScript против других языков: VBScript может говорить только подмножество протокола COM.

еще одно примечание: SOAP "веб-службы" действительно, "вызывающий протокол", как и многие другие веб-протоколы, которые становятся популярными. В конце концов, речь идет о разговоре с кодом, написанным на другом языке (и работающим в другом поле!)


обычно код C++ вызывает интерпретатор для языка сценариев. Степень взаимодействия между скомпилированным и скриптовым кодом зависит от интерпретатора, но всегда есть способ передать данные между ними. В зависимости от интерпретатора можно управлять объектами с одной стороны с другой стороны, например функцией C++, вызывающей метод для объекта Ruby. Может даже быть способ контролировать исполнение одного из другого.


существует протокол для того, как модули общаются. Вот высокий уровень, широкий обзор того, как это работает:

  1. библиотека создана для кода, который вы хотите "поделиться". Они обычно называются DLL или SOs в зависимости от вашей платформы.
  2. каждая функция, которую вы хотите выставить (точка входа), будет доступна для внешнего мира для привязки. Существуют протоколы для привязки, такие как соглашение о вызове, которое определяет порядок передачи параметров, кто очищает стек, сколько параметров будут храниться в регистрах, а какие из них и т. д. Вижу ключевое слово cdecl, нарушением соглашения о стандартном и т. д. Примеры соглашения о вызове здесь.
  3. вызывающий модуль будет статически или динамически привязываться к общей библиотеке.
  4. как только вызывающая библиотека привязана к общей библиотеке, она может указать, что она хочет привязаться к определенной точке входа. Это обычно делается по имени, однако большинство платформ также предлагают вариант привязка по индексу (быстрее, но более хрупкая, если ваш модуль изменяется и точки входа переупорядочиваются).
  5. вы также обычно объявляете функцию, которую вы хотите вызвать в своем модуле, чтобы ваш язык мог выполнять статическую проверку типа,знать, что такое соглашение о вызове и т. д.

для вашего сценария вызова схемы из C++ интерпретатор схемы, скорее всего, экспортирует функцию, которая динамически привязывается к функции/объекту схемы и вызывает ее. Если Модуль схемы компилируется, вероятно, имеет возможность экспортировать точку входа, чтобы ваш модуль c++ мог привязаться к этому. Я не очень хорошо знаком со схемой, поэтому кто-то другой, вероятно, может ответить на специфику этой конкретной привязки лучше, чем я.


вы также можете интегрировать две среды без необходимости компиляции библиотеки интерпретатора внутри исполняемого файла. Вы сохраняете exe и схему exe как отдельные программы в своей системе. Из вашего основного exe вы можете написать код схемы в файл, а затем использовать system() или exec() для запуска интерпретатора схемы. Затем вы анализируете выходные данные интерпретатора схемы.

подход, предложенный выше, держит бывших отдельно, и вам не нужно беспокоиться о третьей стороне зависимости, они могут быть значительными. Также проблемы остаются в одном exe или другом.

Если выполнение отдельного exe не удовлетворяет вашим требованиям производительности, вы можете разработать протокол, где интерпретатор схемы становится сервером. Вам нужно написать некоторые функции схемы, которые ждут ввода в сокет или файл, eval, который вводит, а затем выводит результат в тот же сокет или другой файл. Другой итерацией этого является просмотр существующих серверов, на которых может выполняться ваш интерпретатор уже, например, apache имеет модули, которые позволяют писать код на многих языках.


Если вы на самом деле ищете инструменты, чтобы сделать такую вещь, ответ A la Adam, см. глоток.


с теоретической точки зрения, когда программе A необходимо использовать ресурсы(класс/функции/и т. д.) Из программы B, речь идет о передаче некоторой информации из A В B и возвращении некоторой информации или выполнении некоторых действий. Таким образом, должен быть способ, предоставляемый B, который позволяет A передавать информацию и получать результат.

на практике это обычно лежит на плече языков для обработки этого процесса: язык B (программа B написана) будет генерировать протокол и сделать ресурсы в B доступны предопределенным способом, затем язык A (программа A написана) предоставит некоторую утилиту/структуру, чтобы помочь вызвать открытые ресурсы и получить результаты по протоколу B.

чтобы быть более конкретным к вашему вопросу, для интерпретируемых языков процесс довольно универсален, протокол обычно находится среди строк параметра командной строки, HTTP-запроса и других способов передачи обычного текста. Возьмем первый пример, программа B получит вызов из HTTP-запроса в качестве ввода, а затем обработать запрос оттуда. Фактический формат ввода полностью определяется программой B.

такие вещи, как мыло и т. д., - Это просто способ регулирования программ для ввода данных в общепризнанный стандарт.


прошло лет десять или около того, но я сделал именно это для своего старшего capstone (Ну, я построил нейронную сеть на C и использовал программу схемы, чтобы научить ее). Версия схемы я использовал был составитель, а также переводчик, и мне удалось построить .o файл. Я не знаю версию схемы, которую я запускал, но, похоже, RScheme превратит ваш код схемы в C.