在应用程序中嵌入 C++ 编译器

Posted

技术标签:

【中文标题】在应用程序中嵌入 C++ 编译器【英文标题】:Embed C++ compiler in application 【发布时间】:2014-05-28 08:11:00 【问题描述】:

着色器不是很酷吗?你可以只输入一个纯字符串,只要它是有效的源代码,它就会编译、链接和执行。我想知道是否有办法将 GCC 嵌入到用户应用程序中,使其“自给自足”,例如具有编译与自身兼容的本机二进制文件的内部能力。

到目前为止,我一直在从应用程序内部启动的进程中调用独立的 GCC,但我想知道是否有一些 API 或可以允许“直接”使用而不是独立编译器的东西。另外,如果有可能,是否允许?

编辑:虽然最初的问题是关于 CGG,但我也想了解如何嵌入 LLVM/Clang。

现在,针对无法将 2 + 2 放在一起的人进行特殊编辑:该问题询问如何以允许从代码中使用内部 API 而不是从代码中调用编译的方式将 GCC 或 Clang 嵌入可执行文件中命令提示符。

【问题讨论】:

如果您想在您的应用程序中嵌入 gcc 并分发结果,您可能(与律师交谈以确定)必须根据 GPL 发布它。 【参考方案1】:

我会为使用 Clang/LLVM 而不是 GCC 的建议添加 +1。几个很好的理由:

它更加模块化和灵活 编译时间可以大大低于 GCC 它支持您在 cmets 中列出的平台 它有一个可以在内部使用的 API
string source = "app.c";
string target= "app"; 

llvm::sys::Path clangPath = llvm::sys::Program::FindProgramByName("clang");

// arguments
vector<const char *> args;
args.push_back(clangPath.c_str());
args.push_back(source.c_str());
args.push_back("-l");
args.push_back("curl");

clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
clang::DiagnosticsEngine Diags(DiagID, DiagClient);

clang::driver::Driver TheDriver(args[0], llvm::sys::getDefaultTargetTriple(), target, true, Diags);

clang::OwningPtr<clang::driver::Compilation> c(TheDriver.BuildCompilation(args));

int res = 0;
const clang::driver::Command *FailingCommand = 0;
if (c) res = TheDriver.ExecuteCompilation(*c, FailingCommand);
if (res < 0) TheDriver.generateCompilationDiagnostics(*c, FailingCommand);

【讨论】:

等一下,“clangPath”?这是否意味着 clang::driver::Driver 实际上执行了一个外部“clang”进程? @cap 任何编译器都需要大量的外部资源,例如库和头文件。大多数编译器相对于它们的安装路径来解决这些问题。 看起来代码来自这个网站:fdiv.net/2012/08/15/compiling-code-clang-api【参考方案2】:

是的,有可能,例如,QEMU 做到了。

我在这个领域没有任何个人经验,但从我的阅读来看,LLVM 似乎比 GCC 更适合嵌入和扩展。

【讨论】:

LLVL/Clang 在支持方面正在迎头赶上,并且更加灵活,但 GCC 仍然有更好的平台支持。我已经有一个模块化和可定制的编译器,我需要 GCC 来实现旧版兼容性。 好吧,在这种情况下,您要么必须继续使用当前的方法,要么查看 QEMU 正在做什么。据我所知,GCC 没有一种简单的方法可以将其嵌入到您的项目中(没有稳定的 API,也没有设计为构建为库)。 @user2341104 另一个例子是 GNU Common Lisp。它使用 gcc 编译为 DLL 或 .so 文件并动态链接到当前解释器映像。 gcc 实例是在子进程中调用的,但不是嵌入的。【参考方案3】:

http://www.thefreecountry.com/compilers/cpp.shtml 上提供了一些较旧的 C++ 编译器和解释器列表。

回答“自给自足”的应用程序通常是一个好的语言解释器。其中有很多,很多将代码编译成字节码文件。 Lua language 解释器非常流行且易于嵌入。甚至一些强者use it。

几年前还有一个开源的 C++ 解释器,它具有很好的语言兼容性,从 F.. 开始。不记得名字的其余部分了。还有许多其他工具能够生成本机二进制文件(例如Free Pascal)。

语言和目标平台的选择取决于意图。 “自给自足”有什么好处。谁将编写这些库。一旦你清楚了——使用谷歌——那里就有野生动物。最新的野兽之一是open sourced C# compiler "Roslyn"

编辑

如果您需要一些可以“嵌入”的 C 编译器(当您生成 C 子集时),您可能正在寻找一个 “便携式 C 编译器”,因为您可以put it on USB stick and carry with you。便携式应用程序可以很容易地“嵌入”到其他应用程序中,并且可以很容易地包含在安装程序中。

可能不需要将编译器作为静态链接代码“嵌入”到主应用程序二进制文件中。

https://***.com/questions/7617410/portable-c-compiler-ide SO question 中描述了对便携式 MinGW 的一些参考。

这里有一个集成了 MinGW 的开源 C++ 编辑器https://code.google.com/p/pocketcpp/。

我没有更多话要说,因为我必须去浏览 Google - 所以我不会赢得赏金 :)

【讨论】:

我已经有一个工作翻译。我已经编写了两个编译器,字节码和 C 中间代码,所以我想嵌入一个生产编译器,这样我就不必费心为每个硬件平台编写本机编译器 + 优化。 您必须支持的源语言是什么?目标硬件平台有哪些?哪些是目标操作系统平台?插件代码将解决什么样的问题?嵌入式和独立(您的部署要求)对您来说有什么区别? 它是专有语言,预期平台是 Windows、Linux、MacOS、androidios 上的 x86/x64 和 ARM thumb/v7/v8。诸如 64 位 int/double 值、指针、动态内存分配之类的东西可以是可选的,尽管即使在 ARM M 上也支持大多数,该语言还针对可用的 GLSL 和 OpenCL。自然地,原生编译留给实际的编译器,我只编译成 C 的一个子集作为中间表示。【参考方案4】:

为什么不使用fork()/exec()(适用于类 UNIX 平台)从您的应用程序中调用编译器和链接器?创建一个共享库,然后您可以使用 dlopen() 加载该库。

这避免了可能的许可问题并减轻了您的维护负担。

这是例如varnish 对其configuration files 做了什么;

VCL 语言是一种小型的特定领域语言,旨在用于定义 Varnish Cache 的请求处理和文档缓存策略。

加载新配置时,varnishd 管理进程将 VCL 代码转换为 C 并将其编译为共享对象,然后动态链接到服务器进程。

【讨论】:

以上是关于在应用程序中嵌入 C++ 编译器的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式 Linux 中的 C 与 C++

在 C++ 中嵌入 python

C++ 将外部 .exe 嵌入到我编译的 .exe 中

如何在C或C++代码中嵌入ARM汇编代码

我可以在 VC++ 6.0 编译的应用程序中嵌入 Strawberry Perl 或在编译器不匹配的情况下使用 Inline::C 吗?

如何在网页上运行 C++ 应用程序?