如何将Clang嵌入C++代码作为脚本解释器的教程?

17

我对 LLVM 或 Clang 没有任何经验。根据我所了解的信息,Clang 被称为易于嵌入维基百科-Clang,但是我没有找到任何关于如何实现这一点的教程。因此,在运行时通过 JIT 编译和执行用户定义的代码,是否可以为 C++ 应用程序的用户提供脚本功能?是否可以调用应用程序自己的类和方法并共享对象?

编辑:我希望脚本语言使用类似 C 的语法(甚至是 C++ 本身)。

5个回答

15

我不知道有没有相关教程,但Clang源代码中有一个示例C解释器可能会有所帮助。您可以在这里找到: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/

如果您选择这种方法,您的脚本语言的语法可能并不多样化。Clang只解析C、C++和Objective C。如果您想要任何变化,那么您可能需要付出更多努力。


谢谢。我花了很长时间才让它运行起来 - 主要是因为我没有找到可执行文件 :) 现在经过研究,我认为它已经完成了一半。现在我需要弄清楚如何调用在非即时编译部分定义的函数。...有什么想法吗? - FFox
我不确定你的意思。你应该能够获取到任何已编译函数的指针。也许这个通用的LLVM教程会有所帮助:http://llvm.org/docs/tutorial/(特别是第4章)。我并不期望你能直接使用这个解释器,但它应该能给你一个在应用程序中嵌入C/C++解释器的想法。(我自己甚至都没有使用过它;我只是记得看到过。) - Evan Shaw
2
好的,这是我所做的:http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-July/009836.html ... 并且在cfe-dev邮件列表的热心人的帮助下,它实际上得到了解决。你认为为什么这个解释器不能在应用程序中使用? - FFox
我只是想到你可能需要进行一些自定义或一般性的更改。如果不需要,那就更好了。 - Evan Shaw

7

6
你可以使用clang作为库来实现JIT编译,正如其他答案所述。然后,您需要加载已编译的模块(例如,一个.so库)。
为了实现这一点,您可以使用标准的dlopen(unix)或LoadLibrary(windows)进行加载,然后使用dlsym(unix)动态引用已编译的函数,例如一个类似于“脚本”main()函数的名称已知。请注意,对于C ++,您必须使用mangled符号。
一个可移植的替代方法是GNU的libltdl
作为替代方案,“脚本”可以通过实现模块init函数或放置一些静态代码(C ++全局定义对象的构造函数将立即调用)在加载时自动运行。
加载的模块可以直接调用主应用程序中的任何内容。当然,在编译时使用适当的主应用程序头文件已知符号。
如果您想要轻松地向程序添加C++“插件”,并且预先知道组件接口(假设您的主应用在模块加载到内存之前已经知道了已加载类的名称和接口),那么在动态加载库后,该类可用于像静态链接一样使用。只需要确保在dlopen()其模块之前不尝试实例化类的对象。
使用静态代码还可以实现很好的自动插件注册机制。

1

我不知道Clang,但你可能想看看Ch:

http://www.softintegration.com/

这被描述为可嵌入或独立的C/C++解释器。这里有一篇Dr. Dobbs文章,其中包含嵌入它的示例:

http://www.drdobbs.com/architecture-and-design/212201774

我只是玩了一下,但它似乎是一个稳定和成熟的产品。它是商业闭源的,但“标准”版本被描述为个人和商业使用免费。然而,查看许可证时,似乎“商业”可能仅包括内部公司使用,而不是嵌入到随后出售或分发的产品中。(我不是律师,因此显然应该与SoftIntegration核实许可证条款。)


0

我不确定在你的情况下嵌入类似Clang的C或C++编译器是否是一个好主意。因为“脚本”,也就是(在运行时!)输入的(C或C++)代码可以是任意的,所以有可能会导致整个应用程序崩溃。通常情况下,您不希望错误的用户输入能够使应用程序崩溃。

一定要阅读每个C程序员都应该知道的未定义行为,因为它与C++相关,并适用于您的应用程序使用的任何“C++脚本”。请注意,不幸的是,许多未定义行为不会使进程崩溃(例如缓冲区溢出可能会破坏一些完全无关的数据)。

如果您想嵌入一个解释器,请选择专门为此目的设计的工具,例如GuileLua,并注意脚本中的错误不会导致整个应用程序崩溃。请参阅this answer以获取有关解释器嵌入的更详细讨论。


如果在线程内运行,线程将崩溃而不是主程序。 - Steve Mucci
@SteveMucci:这是特定于操作系统的,通常在Linux上为假:SIGSEGV会中止整个进程。 - Basile Starynkevitch
我刚刚在Linux中使用pthread测试了缓冲区溢出。当将其放入主函数时,溢出会导致整个程序崩溃,但当相同的代码放入线程中时,它并没有崩溃。 - Steve Mucci
@SteveMucci:这只意味着你不够理解未定义行为,以及每个程序员都应该了解的内容 - Basile Starynkevitch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接