我还没有使用 llvm 或 clang 的经验。从我读到的 clang 据说很容易嵌入Wikipedia-Clang,但是,我没有找到任何关于如何实现这一点的教程。那么是否可以通过 JIT 在运行时编译和执行用户定义的代码来为 c++ 应用程序的用户提供脚本功能?是否可以调用应用程序自己的类和方法并共享对象?
编辑:我更喜欢脚本语言的类似 C 的语法(甚至 C++ 本身)
我还没有使用 llvm 或 clang 的经验。从我读到的 clang 据说很容易嵌入Wikipedia-Clang,但是,我没有找到任何关于如何实现这一点的教程。那么是否可以通过 JIT 在运行时编译和执行用户定义的代码来为 c++ 应用程序的用户提供脚本功能?是否可以调用应用程序自己的类和方法并共享对象?
编辑:我更喜欢脚本语言的类似 C 的语法(甚至 C++ 本身)
我不知道任何教程,但 Clang 源代码中有一个示例 C 解释器可能会有所帮助。你可以在这里找到它:http: //llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/
如果你走这条路,你可能不会有太多的脚本语言语法选择。Clang 只解析 C、C++ 和 Objective C。如果你想要任何变化,你可以为你完成你的工作。
我想这就是你所描述的。
您可以使用 clang 作为库来实现 JIT 编译,如其他答案所述。然后,您必须加载已编译的模块(例如,.so 库)。
为了实现这一点,您可以使用标准的 dlopen (unix) 或 LoadLibrary (windows) 来加载它,然后使用 dlsym (unix) 来动态引用已编译的函数,比如名称已知的类似“脚本”main() 的函数. 请注意,对于 C++,您必须使用错位符号。一个可移植的替代方案是例如 GNU 的libltdl。
作为替代方案,“脚本”可以通过实现模块初始化函数或放置一些静态代码在加载时自动运行(将立即调用 C++ 全局定义对象的构造函数)。
加载的模块可以直接调用主应用程序中的任何内容。当然,符号在编译时通过使用适当的主应用程序的头文件是已知的。
如果您想轻松地将 C++“插件”添加到您的程序中,并先验地了解组件接口(例如,在模块加载到内存之前,您的主应用程序从其 .h 中知道已加载类的名称和接口),在您动态加载该类可以使用的库,就好像它是静态链接的一样。请确保在 dlopen() 其模块之前不要尝试实例化类的对象。
使用静态代码也可以实现很好的自动插件注册机制。
我不知道 Clang,但你可能想看看 Ch:
http://www.softintegration.com/
这被描述为可嵌入或独立的 c/c++ 解释器。有一篇 Dobbs 博士的文章,其中包含在此处嵌入的示例:
http://www.drdobbs.com/architecture-and-design/212201774
我没有做的只是玩它,但它似乎是一个稳定而成熟的产品。它是商业的、封闭源代码的,但“标准”版本被描述为免费供个人和商业使用。然而,从许可证来看,“商业”似乎只包括公司内部使用,而不是嵌入到随后销售或分发的产品中。(我不是律师,所以很明显应该与 SoftIntegration 核实以确认许可条款。)
我不确定在您的情况下嵌入像Clang这样的 C 或 C++ 编译器是一个好主意。因为“脚本”,即(C 或 C++)代码(在运行时!)可以是任意的,因此能够使整个应用程序崩溃。您通常不希望错误的用户输入能够使您的应用程序崩溃。
请务必阅读每个 C 程序员应该了解的关于 未定义行为的知识,因为它与 C++ 相关并且也适用于 C++(包括您的应用程序使用的任何“C++ 脚本”)。请注意,不幸的是,许多 UB 不会使进程崩溃(例如,缓冲区溢出可能会破坏一些完全不相关的数据)。
如果您想嵌入解释器,请选择为此目的设计的东西,例如Guile或Lua,并注意脚本中的错误不会导致整个应用程序崩溃。有关解释器嵌入的更详细讨论,请参见此答案。