用一种语言编写的代码如何从另一种语言调用

发布于 2024-07-19 03:46:25 字数 520 浏览 7 评论 0原文

这是我一直想知道答案,却从未真正问过的问题。

由一种语言(尤其是解释性语言)编​​写的代码如何被编译语言编写的代码调用。

例如,假设我正在用 C++ 编写一个游戏,并且我外包了一些要在 Scheme 中编写的 AI 行为。 用Scheme编写的代码如何达到可以被编译后的C++代码使用的程度? C++源代码如何使用它,C++编译代码如何使用它? 使用方式有区别吗?

有关的

多种语言如何在一个项目中交互?< /a>

This is a question that I've always wanted to know the answer, but never really asked.

How does code written by one language, particularly an interpreted language, get called by code written by a compiled language.

For example, say I'm writing a game in C++ and I outsource some of the AI behavior to be written in Scheme. How does the code written in Scheme get to a point that is usable by the compiled C++ code? How is it used by the C++ source code, and how is it used by the C++ compiled code? Is there a difference in the way it's used?

Related

How do multiple-languages interact in one project?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

下雨或天晴 2024-07-26 03:46:25

这个问题没有一个适用于任何地方的单一答案。 一般来说,答案是两种语言必须就“某事”达成一致——一组或规则或“调用协议”。

在高层次上,任何协议都需要指定三件事:

  • “发现”:如何找到彼此。
  • “链接”:如何建立联系(在他们相互了解之后)。
  • “调用”:如何实际向对方提出请求。

细节在很大程度上取决于协议本身。

有时这两种语言会协同工作。 有时,两种语言同意支持某些外部定义的协议。 如今,操作系统或“运行时环境”(.NET 和 Java)也经常被涉及。 有时这种能力只有一种方式(“A”可以调用“B”,但“B”不能调用“A”)。

请注意,这与任何语言在与操作系统通信时面临的问题相同。 Linux内核不是用Scheme写的,你知道的!

让我们看看 Windows 世界中的一些典型答案:

  • C 与 C++:C++ 使用“C 协议”的扭曲(“破坏”)变体。 C++ 可以调用 C,C 也可以调用 C++(尽管名称有时可能非常混乱,并且可能需要外部帮助来翻译名称)。 这不仅仅是Windows; 在支持两者的所有平台上通常都是如此。 大多数流行的操作系统也使用“C 协议”。

  • VB6 与大多数语言:VB6 的首选方法是“COM 协议”。 其他语言必须能够编写可在 VB6 中使用的 COM 对象。 VB6 也可以生成 COM 对象(尽管不是 COM 对象的所有可能变体)。

    VB6 还可以与“C 协议”的非常有限的变体进行通信,然后只能进行外部调用:它无法创建可以通过“C 协议”直接通信的对象。

  • .NET 语言:所有 .NET 语言都将编译通信为相同的低级语言 (IL)。 运行时管理通信,从这个角度来看,它们看起来都像同一种语言。

  • VBScript 与其他语言:VBScript 只能使用 COM 协议的一个子集。

还有一点要注意:SOAP“Web 服务”实际上也是一种“调用协议”,就像许多其他正在流行的基于 Web 的协议一样。 毕竟,这都是关于与用不同语言编写的代码进行对话(并且在不同的盒子中运行!)

There is no single answer to the question that works everywhere. In general, the answer is that the two languages must agree on "something" -- a set or rules or a "calling protocol".

In a high level, any protocol needs to specify three things:

  • "discovery": how to find about each other.
  • "linking": How to make the connection (after they know about each other).
  • "Invocation": How to actually make requests to each other.

The details depend heavily on the protocol itself.

Sometimes the two languages conspire to work together. Sometimes the two languages agree to support some outside-defined protocol. These days, the OS or the "runtime environment" (.NET and Java) is often involved as well. Sometimes the ability only goes one way ("A" can call "B", but "B" cannot call "A").

Notice that this is the same problem that any language faces when communicating with the OS. The Linux kernel is not written in Scheme, you know!

Let's see some typical answers from the world of Windows:

  • C with C++: C++ uses a contorted ("mangled") variation of the "C protocol". C++ can call into C, and C can call into C++ (although the names can be quite messy sometimes and it might need external help translating the names). This is not just Windows; it's generally true in all platforms that support both. Most popular OS's use a "C protocol" as well.

  • VB6 vs. most languages: VB6's preferred method is the "COM protocol". Other languages must be able to write COM objects to be usable from VB6. VB6 can produce COM objects too (although not every possible variation of COM objects).

    VB6 can also talk a very limited variation of the "C protocol", and then only to make calls outside: it cannot create objects that can be talked to directly via the "C protocol".

  • .NET languages: All .NET languages communicate compile to the same low-level language (IL). The runtime manages the communication and from that point of view, they all look like the same language.

  • VBScript vs. other languages: VBScript can only talk a subset of the COM protocol.

One more note: SOAP "Web Services" is really a "calling protocol" as well, like many other web-based protocol that are becoming popular. After all, it's all about talking to code written in a different language (and running in a different box at that!)

烟柳画桥 2024-07-26 03:46:25

通常,C++ 代码将调用脚本语言的解释器。 编译代码和脚本代码之间的交互程度取决于解释器,但总有一种方法可以在两者之间传递数据。 根据解释器的不同,可能可以从另一侧操作一侧的对象,例如 C++ 函数调用 Ruby 对象上的方法。 甚至可能有一种方法可以控制其中一个的执行。

Typically the C++ code will invoke an interpreter for the scripting language. The degree of interaction between the compiled and scripting code is dependent on the interpreter but there's always a way to pass data between the two. Depending on the interpreter, it may be possible to manipulate the objects on one side from the other side, such as a C++ function calling a method on a Ruby object. There may even be a way to control execution of one from the other.

染火枫林 2024-07-26 03:46:25

有一个关于模块如何通信的协议。 以下是其工作原理的高级、广泛概述:

  1. 为您想要“共享”的代码创建一个库。 这些通常称为 DLL 或 SO,具体取决于您的平台。
  2. 您想要公开的每个函数(入口点)都可供外界绑定。 有一些关于如何绑定的协议,例如指定参数传递顺序的调用约定、谁清理堆栈、寄存器中存储了多少参数以及哪些参数等。有关调用的示例,请参阅 cdecl、stdcall 等约定此处
  3. 然后,调用模块将静态或动态绑定到共享库。
  4. 一旦您的调用库绑定到共享库,它就可以指定它想要绑定到特定的入口点。 这通常是通过名称完成的,但是大多数平台还提供通过索引绑定的选项(如果模块发生更改并且入口点重新排序,速度会更快,但会更脆弱)。
  5. 您通常还会在模块中的某处声明要调用的函数,以便您的语言可以进行静态类型检查、知道调用约定是什么等。

对于从 C++ 调用Scheme 的场景,Scheme 解释器很可能会导出一个函数动态绑定到计划函数/对象并调用它。 如果Scheme模块被编译,它可能可以选择导出一个入口点,这样你的C++模块就可以绑定到它。 我对Scheme不太熟悉,所以其他人可能可以比我更好地回答该特定绑定的细节。

There is a protocol for how modules communicate. Here is a high-level, broad overview of how it works:

  1. A library is created for code you want to 'share'. These are commonly called DLLs or SOs depending on your platform.
  2. Each function you want to expose (entry point) will be available to the outside world to bind to. There are protocols to how to bind such as the calling convention which specifies the order the parameters are passed, who cleans up the stack, how many parameters get stored in registers and which ones, etc. See cdecl, stdcall, etc for examples of calling conventions here.
  3. The calling module will then either statically or dynamically bind to the shared library.
  4. Once your calling library is bound to the shared library it can then specify it wants to bind to a particular entry point. This is generally done by name, however most platforms also offer the option of binding by index (faster, yet more brittle if your module changes and entry points are reordered).
  5. You will also generally declare the function you want to call in your module somewhere so that your language can do static type checking, knows what the calling convention is etc.

For your scenario of calling Scheme from C++, the Scheme interpreter most likely exports a function that dynamically binds to a Scheme function/object and calls that. If the Scheme module is compiled it probably has the option of exporting an entry point so your C++ module could bind to that. I am not very familiar with Scheme so someone else can probably answer the specifics of that particular binding better than I.

安人多梦 2024-07-26 03:46:25

您还可以集成这两个环境,而无需在可执行文件中编译解释器的库。 您将 exe 和计划 exe 作为单独的程序保留在系统上。 从主 exe 中,您可以将方案代码写入文件,然后使用 system() 或 exec() 运行方案解释器。 然后,您可以解析方案解释器的输出。

上面建议的方法使 EXE 保持独立,您不必担心第 3 方依赖项,它们可能很重要。 而且问题仍然包含在一个或另一个可执行文件中。

如果运行单独的 exe 不能满足您的性能要求,您可以设计一个协议,其中方案解释器成为服务器。 您需要编写一些Scheme函数来等待套接字或文件上的输入,评估该输入,然后将结果输出到同一套接字或不同的文件。 另一个迭代是查看可能已经运行解释器的现有服务器,例如 apache 具有允许用多种语言编写代码的模块。

You can also integrate the two environments without having to compile the interpreter's library inside your executable. You keep your exe and the Scheme exe as separate programs on your system. From your main exe you can write your Scheme code to a file then use system() or exec() to run the scheme interpreter. You then parse the output of the scheme interpreter.

The approach suggested above keeps the exes separate and you do not have to worry about 3rd party dependencies, they can be significant. Also problems stay contained in one exe or another.

If running a separate exe does not satisfy your performance requirements you can devise a protocol where the Scheme interpreter becomes a server. You need to write some Scheme functions that wait for input on a socket or file, eval that input then output the result to the same socket or a different file. Another iteration of this is to look at existing servers that may be running your interpreter already, for example apache has modules that allows code to be written in many languages.

爱的故事 2024-07-26 03:46:25

如果您确实正在寻找执行此类操作的工具(如 Adam 的回应),请参阅 swig

If you're actually looking for tools to do such a thing, a la Adam's response, see swig.

沦落红尘 2024-07-26 03:46:25

从理论上来看,当程序A需要使用程序B的资源(类/函数/等)时,就是从A向B传递一些信息,并获取一些信息或执行一些操作。 所以需要B提供一种方式让A传入信息并得到结果。

在实践中,通常由语言来处理这个过程:语言B(编写程序B的语言)将生成一个协议并以预定义的方式使B中的资源可用,然后语言A(编写程序A的语言) )将提供一些实用程序/框架来帮助调用公开的资源并按照 B 的协议获得结果。

更具体地说,对于解释型语言,该过程是相当通用的,协议通常位于命令行参数、HTTP 请求和其他传输纯文本的方式之间。 以第一个例子为例,程序B将接收来自HTTP请求的调用作为输入,然后处理该请求。 输入的实际格式完全由程序B决定。

像SOAP等,只是规范程序以共同商定的标准接受输入的一种方式。

From a theoretical point of view, when program A need to use resources(class/functions/etc) from program B, it's about passing in some information from A to B, and get some information back or some actions performed. So there needs to be a way provided by B that allows A to pass in information and get result.

In practice, it usually lies on the shoulder of languages to handle this process: the language B(program B is written in) will generate a protocol and make resources in B available in a predefined way, then language A(program A is written in) will provide some utility/framework to help invocate the exposed resources and get results following B's protocol.

To be more specific to your question, for interpreted languages, the process is fairly universal, the protocol is normally among the lines of command line parameter, HTTP request and other ways of transmitting plain text. Take the first example, program B will receive a call from HTTP request as input, and then process the request from there on. The actual format of input is totally decided by program B.

Things like SOAP and etc, are just a way to regulate programs to take input in a commonly agreed standard.

不顾 2024-07-26 03:46:25

已经有十年左右的时间了,但我正是为我的高级顶点所做的(嗯,我用 C 语言构建了一个反向传播神经网络,并使用了一个方案程序来教授它)。 我使用的方案版本有一个编译器和一个解释器,我能够将其构建为 .o 文件。 我不知道我正在运行的方案版本,但看起来 RScheme 会将您的方案代码转换为 C。

It's been a decade or so, but I did exactly this for my senior capstone (Well, I built a back-propogating neural network in C, and used a scheme program to teach it). The version of Scheme I was using had a compiler as well as an intepreter, and I was able to build it as a .o file. I don't know the version of scheme I was running, but it appears the RScheme will turn your scheme code into C.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文