1

假设您正在为一种名为 Foo 的新语言设计和编写编译器,它的优点之一是它特别适合实现编译器。一个经典的方法是用 C 编写编译器的第一个版本,然后用它用 Foo 编写第二个版本,之后它就可以自编译了。

这确实意味着您必须小心保留二进制文件的备份副本(与大多数程序相反,您只需保留源的备份副本);一旦语言从第一个版本演变而来,如果您丢失了二进制文件的所有副本,您将无法编译当前版本。随它吧。

但假设它旨在同时支持 Linux 和 Windows。只要它实际上在两个平台上都运行,它可以在每个平台上自行编译,没问题。然而,假设您在一个平台上丢失了二进制文件(或有理由怀疑它已被攻击者破坏);现在有一个问题。并且必须为每个受支持的平台保护二进制文件至少比我能接受的故障点多一个。

一种解决方案是让它成为一个交叉编译器,这样任何一个平台上的二进制文件都可以针对这两个平台。

这并不像听起来那么容易 - 虽然选择二进制输出格式没有问题,但每个平台都以 C 头文件的形式提供系统 API,这些头文件通常只存在于它们的本机平台上,例如没有保证代码stdio.h即使编译成 Linux 二进制格式,针对 Windows 编译也可以在 Linux 上运行。

也许这个问题可以通过将 Linux 头文件下载到 Windows 机器上并使用 Windows 二进制文件交叉编译 Linux 二进制文件来解决。

我缺少该解决方案是否有任何警告?

另一种解决方案可能是在 Python 中维护一个单独的最小引导编译器,它将 Foo 编译成可移植的 C,只接受主 Foo 编译器所需的语言子集并执行最小错误检查而不进行优化,目的是引导编译器因此将保持足够简单,以便在后续语言版本中维护它不会花费太多。

同样,我缺少该解决方案是否有任何警告?

过去人们用什么方法来解决这个问题?

4

1 回答 1

3

这是 C 编译器本身的问题。它通常完全按照您的建议通过使用交叉编译器来解决。

交叉编译编译器的过程并不比交叉编译任何其他项目更困难:也就是说,它比您想要的要复杂,但绝不是不可能的。

当然,您首先需要交叉编译器本身。这可能意味着对您的构建配置系统进行一些大手术,并且您需要从目标中获取某种“sysroot”(标头,库,您需要在构建中引用的任何其他内容)。

因此,最终这取决于您的编译器的结构。要么使用历史源重新引导更容易,重复你首先经历的语言兼容性的每个阶段(你确实使用了源版本控制,对吗?),或者更容易实现交叉编译器配置。我不能告诉你从这里是哪个。

多年来,GCC 编译器总是只用符合标准的 C 代码编写,正是因为这个原因:他们希望能够在任何操作系统上启动它,只给该系统的本机 C 编译器。直到 2012 年,它才决定 C++ 现在已经足够广泛,编译器本身可以用它来编写。即使这样,他们也只允许自己使用该语言的一个子集。将来,如果有人想将 GCC 移植到还没有 C++ 的平台,他们将需要使用交叉编译器,或者首先移植 GCC 4.7(最后一个主要的 C-only 版本),然后迁移到最新的.

此外,GCC 构建过程并不“信任”它构建时使用的编译器。当您键入“make”时,它首先构建自身的简化版本,然后使用该构建的完整版本。最后,它使用完整版本重建另一个完整版本,并比较两个二进制文件。如果两者不匹配,它就知道原始编译器有错误并引入了一些错误代码,并且构建失败。

于 2013-02-04T15:25:40.380 回答