“GCC Cross-Compiler”的版本间差异

来自osdev
跳到导航 跳到搜索
第1行: 第1行:
{{FirstPerson}}
{{FirstPerson}}
{{rating|1}}
{{rating|1}}
本教程重点介绍为您自己的操作系统创建GCC交叉编译器。 我们在这里构建的编译器将有一个通用目标(i686 elf),它允许您将当前操作系统留在后面,这意味着不会使用主机操作系统的头或库。 在操作系统开发中,您“需要”一个交叉编译器,否则会发生很多意想不到的事情,因为编译器假定您的代码正在主机操作系统上运行。
本教程重点介绍为开发自制操作系统创建所需的GCC交叉编译器。(译者注:本文中“自己的、自制的”都是说目标操作操作) 我们在这里构建的编译器有一个一般目标(i686-ELF),交叉编译器允许你的编译结果脱离当前操作系统,这意味着不会使用主机操作系统(Host OS)的引用头或库。 你 ''需要''使用交叉编译器来进行操作系统开发,否则可能会发生很多意想不到的事情,因为一般编译器默认会假设你的代码应该在你的当前主机操作系统上运行。


== 介绍 ==
==导言==


一般来说,交叉编译器是在平台a(“主机”)上运行,但为平台B(“目标”)生成可执行文件的编译器。这两个平台在CPU、操作系统和/或[:类别:可执行格式|可执行格式]]方面可能(但不需要)有所不同。 在我们的例子中,主机平台是您当前的操作系统,目标平台是您将要制作的操作系统。 重要的是要认识到这两个平台是不同的;您正在开发的操作系统总是与您当前使用的操作系统不同。 这就是为什么我们需要首先构建一个交叉编译器,否则您肯定会遇到麻烦。
简单来说,交叉编译器是指在平台A('''Host主机''')上运行,但为平台B('''Traget目标''')生成可执行文件的编译器。 这两个平台可能 (但不一定) 在CPU、操作系统以及[[:Category:Executable Formats|可执行格式]]方面有所不同。 在我们的例子中,主机平台是你当前的操作系统,目标平台是你即将制作的操作系统。 重要的是要认识到,这两个平台是不同的;你正在开发的操作系统总是不同于你当前使用的操作系统。 这就是为什么我们需要首先构建一个交叉编译器,否则你肯定会遇到麻烦。


=== 为什么需要交叉编译器 ===
===为什么需要交叉编译器===
{{Main|Why do I need a Cross Compiler?}}
{{Main|Why do I need a Cross Compiler?}}


您需要使用交叉编译器“”,除非您在自己的操作系统上开发“”。 编译器必须知道正确的目标平台(CPU、操作系统),否则您将遇到麻烦。 如果您使用系统附带的编译器,那么编译器不会知道它正在编译其他的东西。 一些教程建议使用系统编译器,并向编译器传递许多有问题的选项。 这在将来肯定会给您带来很多问题,解决方案是构建一个交叉编译器。 如果您已经尝试在不使用交叉编译器的情况下创建操作系统,请阅读文章[[为什么我需要交叉编译器?]]。
''除非''是在自制的操作系统上进行开发,否则你需要使用交叉编译器。 编译器必须知道正确的目标平台 (CPU,操作系统),否则你将遇到麻烦。 如果你使用系统附带的编译器,那么编译器将不会知道它正在完全编译其他平台的内容。 一些其它教程会建议使用你的系统已有编译器,并将许多特殊的选项传递给编译器。 这肯定会在将来给你带来很多问题,正确的解决方案应该是构建一个交叉编译器。 如果你已经尝试在不使用交叉编译器的情况下创建操作系统,请阅读文章[[Why do I need a Cross Compiler?|为什么我需要交叉编译器?]]。


=== 选择哪个编译器版本 ===
===选择哪个编译器版本===
{{Main|Building GCC}}
{{Main|构建GCC}}


建议使用最新的[[GCC]],因为它是最新和最棒的版本。 例如,如果使用GCC4.6,您可能会遇到麻烦。3构建GCC4.8。0交叉编译器。 如果您的系统编译器没有使用最新的主要GCC版本,我们建议您[[构建GCC |构建最新的GCC作为系统编译器]]。
推荐使用最新的[[GCC]],因为它是最新和最好的版本。(译者注:这里指的是用什么编译器和源代码编译出新的‘交叉编译器’) 例如,使用GCC 4.6.3构建GCC 4.8.0交叉编译器可能会遇到麻烦。 如果你的系统编译器没有使用最新的主要GCC版本,我们建议你 [[Building GCC| 构建最新的GCC作为你的系统编译器]]。


您也可以使用较旧的版本,因为它们通常相当好。 如果您的本地系统编译器不是太旧(至少GCC4.6.0),您可能希望省去麻烦,只需为交叉编译器选择最新的次要版本(如4.6.3,如果您的系统编译器是4.6.1)。
你也可以使用旧版本,因为它们通常相当好。 如果你的本地系统编译器不是太旧(至少是GCC 4.6.0),你可能希望省去麻烦,只为你的交叉编译器选择非最新的版本(例如,如果你的系统编译器是4.6.1,则为选4.6.3为交叉编译器源代码版本)。


您可以通过调用以下命令查看当前编译器版本:
你可以通过调用以下代码查看你当前的编译器版本:


gcc--version</source lang=“bash”>
<source lang="bash">gcc --version</source>


您可以使用较旧的主要GCC版本来构建较新的主要GCC版本的交叉编译器。 例如,GCC4.7。3可能能够构建GCC4.8。0交叉编译器。 但是,如果您想在交叉编译器中使用最新和最好的GCC版本,我们建议您首先[[构建GCC |引导最新的GCC]]作为系统编译器。 使用OS X 10.7或更早版本的个人可能希望投资构建系统GCC(输出本机Mach-O),或者升级本地LLVM/Clang安装。 10.8及以上版本的用户应该从苹果开发者网站安装命令行工具,并使用Clang交叉编译GCC。
你可以使用较旧的GCC主版本来构建较新的GCC主版本的交叉编译器。 例如,GCC 4.7.3也许能够构建GCC 4.8.0版的交叉编译器。 但是,如果你想为交叉编译器使用最新最好的GCC版本,我们建议你首先将 [[Building GCC |启动最新GCC]] 作为系统编译器。 使用OS X 10.7或更早版本的个人可能需要即构建系统GCC(输出本机Mach-O),也要升级本地LLVM/Clang安装。 10.8及以上版本的用户应从苹果开发者网站安装命令行工具,并使用Clang交叉编译GCC。


=== 要选择哪个binutils版本 ===
=== 选择哪个binutils版本 ===
{{Main|Cross-Compiler Successful Builds}}
{{Main|Cross-Compiler Successful Builds}}
我们建议您使用最新和最好的[[Binutils]]版本。但是,请注意,并非所有GCC和Binutils的组合都有效。如果遇到问题,请使用与所需编译器版本大致同时发布的Binutils。您可能至少需要Binutils 2.22,或者最好是最新的2.23。2释放。在当前操作系统上安装的Binutils版本并不重要。例如,您可以通过以下命令找到binutils版本:
我们建议你使用最新最好的[[Binutils]]发行版。 然而,请注意,并不是所有GCC和Binutils的组合都有效。 如果遇到麻烦,请使用与所需编译器版本大致同时发布的Binutils。 你可能至少需要Binutils 2.22,或者最好是最新的2.23.2版本。 你在当前操作系统上安装的Binutils版本并不重要。 你可以通过以下命令找到binutils版本:
<source lang="bash">ld --version</source>
<source lang="bash">ld --version</source>


=== 确定目标平台 ===
===决定目标平台===
{{Main|Target Triplet}}
{{Main|Target Triplet}}


你应该已经知道了。 如果您正在学习[[Bare Bones]]教程,则希望为<tt>i686 elf</tt>构建交叉编译器。
你应该已经明确知道自己的目标平台了。 如果你正在学习[[Bare Bones]]教程,那么你应该是希望为<tt>i686 elf</tt>构建一个交叉编译器。


=== 关于arm none eabi gcc的注释 ===
=== 注意arm-none-eabi-gcc ===
apt get for Debiab/Ubuntu上有一个预构建的包gcc arm none eabi,但您不应该使用它,因为它既不包含libgcc,也不包含libgcc。也不是像stdint这样的独立C头文件。h、 <br>
在Debiab/Ubuntu上的apt-get中有预构建的包gcc-arm-none-eabi,但是你不应该使用它,因为它既不包含libgcc.a,也不包含像stdint.h这样的独立的C头文件。<br>
相反,您应该使用<tt>arm none eabi</tt>作为$TARGET自己构建它。
相反,你应该自己用<tt>arm-none-eabi</tt>作为$TARGET来构建它。


== 为构建做准备 ==
==为构建做准备==
<!-- Note how this section ([[Preparing GCC Build]]) is shared by [[Building GCC]] and [[GCC Cross-Compiler]]. -->
<!-- Note how this section ([[Preparing GCC Build]]) is shared by [[Building GCC]] and [[GCC Cross-Compiler]]. -->
{{:Preparing GCC Build}}
{{:Preparing GCC Build}}


== 建造 ==
==构建==


我们构建了一个在主机上运行的工具集,可以将源代码转换为目标系统的目标文件。
我们计划构建一个在你的主机上运行的工具集,可以将源代码转换为目标系统的目标文件。


您需要决定在何处安装新编译器。 将其安装到系统目录中是危险的,也是一个非常糟糕的主意。 您还需要决定是全局安装新编译器,还是仅为您安装。 如果您只想安装它(推荐),安装到<tt>$HOME/opt/cross</tt>通常是个好主意。 如果您想在全球范围内安装它,将其安装到<tt>/usr/local/cross</tt>通常是个好主意。
你需要决定在哪里安装你的新编译器。 将其安装到系统目录中的做法既危险又糟糕。 你还需要决定是应该全局安装新编译器,还是只为个人单用户安装新编译器。 如果你只想为自己安装 (推荐),则通常比较好的主意将其安装到 <tt>$ HOME/opt/cross</tt> 中。 如果你想在全局安装它,则最好通常将其安装到<tt>/usr/local/cross</tt>


请注意,我们从源目录树构建所有内容,这被认为是良好的实践。 有些软件包只支持外部构建,有些软件包只支持内部构建,有些软件包两者都支持(但可能不提供make的广泛检查)。在源目录树中构建GCC失败得很惨,至少对于旧版本是如此。
请注意,我们最好在源代码目录树之外构建所有内容。 有些软件包仅支持外部构建,有些仅支持内部建筑,有些则两者兼而有之 (但可能无法对构建过程进行广泛的检查)。 在源目录树中构建GCC会失败得很惨,至少对于旧版本来说是如此。


=== 准备 ===
===准备===


<source lang="bash">
<source lang="bash">
第59行: 第59行:
</source>
</source>


我们将安装前缀添加到当前shell会话的<tt>路径中。 这确保编译器构建能够在构建新的binutil之后检测它们。
我们将安装前缀(PREFIX)添加到当前shell会话的 <tt>PATH</tt> 中。 这确保了一旦我们构建了新的binutil,编译器构建就能够检测它们。


前缀将配置构建过程,以便交叉编译器环境中的所有文件最终都位于$HOME/opt/cross中。 您可以将该前缀更改为您喜欢的任何前缀(例如,/opt/cross或$HOME/cross将是选项)。 如果您具有管理员访问权限并希望使交叉编译器工具链可供所有用户使用,则可以将其安装到/usr/local prefix中,或者如果您愿意更改系统配置,使此目录位于所有用户的搜索路径中,则可以将其安装到/usr/local/cross prefix中。从技术上讲,您甚至可以直接安装到/usr,这样您的交叉编译器将与系统编译器一起驻留,但由于以下几个原因,不建议这样做(例如,如果目标错误,可能会覆盖系统编译器,或者与系统的包管理发生冲突)。
前缀将配置构建过程,以便你的交叉编译器环境的所有文件都以$HOME/opt/cross开头。 你可以将该前缀更改为你喜欢的任何内容 (例如,/opt/cross或 $HOME/cross 都可以)。 如果你具有管理员权限,并且希望所有用户都可以使用交叉编译器工具链,则可以将其安装到/usr/local前缀中 - 或者,如果你愿意更改系统配置,使此目录位于所有用户的搜索路径中,也可以使用/usr/local/cross前缀。 从技术上讲,你甚至可以直接安装到/usr,这样你的交叉编译器将与你的系统编译器一起驻留,但由于各种原因,不建议你这样做 (例如,如果目标错误,可能会覆盖系统编译器,或者与系统的包管理发生冲突)。


=== 比努蒂尔斯 ===
===Binutils===
<!--
<!--
这让一些人有点困惑,他们应该通过包管理获得它,并遵循上面的说明。
This confuses some people a bit too much and they should just get it through package management and follow the above instructions.
#如果您希望将这些包构建为binutils的一部分:
# If you wish to build these packages as part of binutils:
mv isl-x.y.z binutils-x.y.z/isl
mv isl-x.y.z binutils-x.y.z/isl
mv cloog-x.y.z binutils-x.y.z/cloog
mv cloog-x.y.z binutils-x.y.z/cloog
第81行: 第81行:
</source>
</source>


这将编译binutils(汇编程序、反汇编程序和各种其他有用的东西),可以在系统上运行,但可以以$TARGET指定的格式处理代码。
这将编译binutils (汇编程序,反汇编程序和其他各种有用的东西),它们可在你的系统上运行,但以$TARGET指定的格式处理代码。


'''--disable-nls''' tells binutils not to include native language support. This is basically optional, but reduces dependencies and compile time. It will also result in English-language diagnostics, which the people on the [http://forum.osdev.org/ Forum] understand when you ask your questions. ;-)
'''--disable-nls'''告诉binutils不要包含本机语言支持。 这基本上是可选的,但可以减少依赖性和编译时间。 这也会影响诊断结果的英文,当你提出问题时,[http://forum.osdev.org/ 论坛] 上的人们会理解。;-) (译者注:没有作者Get意思)


'''--with-sysroot''' tells binutils to enable sysroot support in the cross-compiler by pointing it to a default empty directory. By default, the linker refuses to use sysroots for no good technical reason, while gcc is able to handle both cases at runtime. This will be useful later on.
'''--with-sysroot'''告诉binutils在交叉编译器中启用sysroot支持,方法是将其指向默认的空目录。 默认情况下,因为没有很好的技术原因,链接器拒绝使用sysroot,而GCC能够在运行时处理这两种情况。 这将在以后有用。


=== GCC ===
===GCC===
:''See also the [http://gcc.gnu.org/install/configure.html offical instructions for configuring gcc].''
''另请参阅[http://gcc.gnu.org/install/configure.html 配置GCC的官方说明]''


现在,您可以构建[[GCC]]
现在,你可以开始构建 [[GCC]]了。
<!--
<!--
这让一些人有点困惑,他们应该通过包管理获得它,并遵循上面的说明。
This confuses some people a bit too much and they should just get it through package management and follow the above instructions.
#如果您希望将这些包构建为gcc的一部分:
# If you wish to build these packages as part of gcc:
mv libiconv-x.y.z gcc-x.y.z/libiconv#Mac OS x用户
mv libiconv-x.y.z gcc-x.y.z/libiconv # Mac OS X users
mv gmp-x.y.z gcc-x.y.z/gmp
mv gmp-x.y.z gcc-x.y.z/gmp
mv mpfr-x.y.z gcc-x.y.z/mpfr
mv mpfr-x.y.z gcc-x.y.z/mpfr
第100行: 第100行:
mv isl-x.y.z gcc-x.y.z/isl
mv isl-x.y.z gcc-x.y.z/isl
mv cloog-x.y.z gcc-x.y.z/cloog
mv cloog-x.y.z gcc-x.y.z/cloog
#但请重新考虑:您应该从操作系统中获取开发包。
# But reconsider: You should just get the development packages from your OS.
-->
-->


第118行: 第118行:
</source>
</source>


We build [[libgcc]], a low-level support library that the compiler expects available at compile time. Linking against [[libgcc]] provides integer, floating point, decimal, stack unwinding (useful for exception handling) and other support functions. Note how we are ''not'' simply running <tt>make && make install</tt> as that would build way too much, not all components of gcc are ready to target your unfinished operating system.
我们构建[[libgcc]],这是一个低级支持库,编译器希望它在编译时可用。 针对[[libgcc]]的链接提供整数、浮点、小数、堆栈展开(用于异常处理)和其他支持功能。 请注意,我们这里''没有''简单地运行 <tt>make && make install</tt>,因为这会构建太多的方式,并不是gcc的所有组件都针对你未完成的操作系统已准备好。


'''--disable-nls''' is the same as for binutils above.
'''--disable-nls''' 与上面的binutils相同。


'''--without-headers''' tells [[GCC]] not to rely on any C library (standard or runtime) being present for the target.
'''--without-headers'''告诉[[GCC]]不要为目标依赖任何存在的C库(标准库或运行时库)


'''--enable-languages''' tells [[GCC]] not to compile all the other language frontends it supports, but only C (and optionally C++).
'''--enable-languages''' 告诉 [[GCC]] 不要编译它支持的所有其他语言前端,而只能编译C (以及可选的C++)


It will take a while to build your cross-compiler.
构建交叉编译器需要一段时间。


If you are building a cross compiler for x86-64, you may want to consider building Libgcc without the "red zone": [[Libgcc_without_red_zone]]
如果你正在构建x86-64的交叉编译器,则可能需要考虑构建不带“red zone”的Libgcc:[[Libgcc_Without_red_zone]]


== 使用新编译器 ==
== 使用新的编译器 ==


现在您有了一个“裸”交叉编译器。它还没有访问C库或C运行时的权限,因此您不能使用任何标准包含或创建可运行的二进制文件。但是编译不久将要制作的内核就足够了。您的工具集驻留在$HOME/opt/cross(或您设置的<tt>$PREFIX</tt>中)。例如,您有一个GCC可执行文件,安装为<tt>$HOME/opt/cross/bin/$TARGET GCC</tt>,它为您的目标创建程序。
现在你有了一个“裸”交叉编译器。 它还不能访问C库或C运行时,因此你不能使用任何标准的包含语句或创建可运行的二进制文件。 但是编译你将马上要制作的内核已经足够了。 你的工具集位于$HOME/opt/cross(或你设置的<tt>$PREFIX</tt>中)。 例如,你将GCC可执行文件安装为<tt>$HOME/opt/cross/bin/$TARGET-gcc</tt>,它将为你的目标创建程序。


现在,您可以通过调用以下命令来运行新编译器:
你现在可以通过调用类似的东西来运行你的新编译器:


<source lang="bash">$HOME/opt/cross/bin/$TARGET-gcc --version</source>
<source lang="bash">$HOME/opt/cross/bin/$TARGET-gcc --version</source>


请注意此编译器如何“无法”编译普通C程序。只要你想包含任何标准头,交叉编译器就会抛出错误(除了少数几个真正独立于平台的、由编译器自己生成的头)。这是非常正确的-您还没有针对目标系统的标准库!
请注意,此编译器“无法”编译普通C程序。 每当你想要#include包含任何标准标头时,交叉编译器都会产生错误(除了少数实际上独立于平台并由编译器本身生成的标头)。 这是对于操作系统开发是非常必要的-你还没有目标系统的标准库!


C标准定义了两种不同的执行环境——“独立”和“托管”。虽然对于一般的应用程序程序员来说,这个定义可能相当模糊,但在进行操作系统开发时却非常明确:内核是“独立的”,在用户空间中所做的一切都是“托管的”。“独立”环境只需要提供C库的一个子集:float。h、 iso646。h、 限制。h、 stdalign。h、 斯塔格。h、 stdbool。h、 stddef。h、 斯特丁。h和stdnoreturn。h(从C11开始)。所有这些都由typedef s和#define s“only”组成,因此您可以在不使用单个函数的情况下实现它们。看到c文件了。
C标准定义了两种不同的执行环境——“独立freestanding”和“托管hosted”。 虽然对于普通的应用程序程序员来说,这个定义可能相当模糊,但是当你进行操作系统开发时,它是相当清晰的: 内核执行是 “独立的”,你在用户空间中做的一切都是 “托管的”。 “独立”环境只需要提供C库的一个子集:float.h、 iso646.h、 limits.h、 stdalign.h、 stdarg.h、 stdbool.h、 stddef.h, stdint.h和stdnoreturn.h(从C11开始)。 所有这些文件都“仅仅”由typedef s和#define s 组成,因此你可以在看不到一个.c文件的情况下使用它们。


要通过调用<tt>$TARGET gcc</tt>使用新编译器,请通过键入以下内容将<tt>$HOME/opt/cross/bin</tt>添加到<tt>$PATH</tt>
要简单地通过调用 <tt>$TARGET-gcc</tt> 来使用你的新编译器,请通过键入将 <tt>$ HOME/opt/cross/bin</tt> 添加到你的 <tt>$PATH</tt> 中:


<source lang="bash">export PATH="$HOME/opt/cross/bin:$PATH"</source>
<source lang="bash">export PATH="$HOME/opt/cross/bin:$PATH"</source>


此命令将把新编译器添加到此shell会话的路径中。 如果希望永久使用,请将PATH命令添加到<tt>~/。配置文件</tt>配置shell脚本或类似文件。 有关更多信息,请参阅shell文档。
此命令将把新编译器添加到此shell会话的路径中。 如果你希望永久使用它,请将path命令添加到你的<tt>~/.profile</tt>配置shell脚本或类似脚本中。 有关更多信息,请参阅你的shell文档。


现在,您可以继续完成[[Bare Bones]]教程变体,并使用新的交叉编译器完成它。 如果您构建了一个新的GCC版本作为系统编译器,并使用它来构建交叉编译器,那么您现在可以安全地卸载它,除非您希望继续使用它。
如果是你是从[[Bare Bones]]教程来到这里,那么现在你可以再使用新的交叉编译器来完成它,实现一个新的变体。 如果你开始是构建了一个新的GCC版本作为系统编译器,并使用它来构建出了交叉编译器,那么你现在可以安全地卸载那个系统编译器,除非你希望继续使用它。


== 故障排除 ==
== 故障排除 ==


通常,“验证”您是否仔细阅读了说明并准确键入了命令。 不要跳过说明。 如果您使用一个新的shell实例,如果您没有通过将其添加到shell概要文件中使其永久化,那么您必须再次设置PATH变量。 如果编译似乎真的搞砸了,请键入make distclean,然后重新开始make过程。 确保您的un archiever不会更改换行符。
一般来说,这里要'''验证'''的仅是你仔细阅读了说明,并准确键入了命令。 不要跳过说明。 如果你使用新的shell实例,如果你没有将其添加到shell配置文件中,则必须再次设置PATH变量。 如果编译过程似乎真的搞砸了,请键入<tt>make distclean</tt>,然后重新开始make过程。 确保你的解压软件不会更改换行符。


==== ld: cannot find -lgcc ====
==== ld: 找不到 -lgcc ====


您指定要通过<tt>-lgcc</tt>'开关将GCC低级运行库链接到可执行文件中,但忘记构建并正确安装库<br>
你通过<tt>-lgcc</tt>开关将GCC低级运行库链接到可执行文件中,但忘记了构建和正确安装库<br>
如果在安装libgcc时没有收到警告或错误,但仍然存在问题,则可以在项目中复制库并将其链接到<tt>-L.-lgcc</tt><br>
如果在安装libgcc时没有收到任何警告或错误,但仍然存在问题,则可以将库复制到项目中并将其用<tt>-L. -lgcc</tt><br>链接
libgcc位于$PREFIX/lib/gcc/$TARGET/<gcc version>/libgcc。A.
libgcc位于 $PREFIX/lib/gcc/$TARGET/<gcc-version>/libgcc.a。


==== Binutils 2.9 ====
==== Binutils2.9 ====


按字母顺序排列在顶部或底部的内容不一定是最新版本。 在2.9之后是2.10、2.11、2.12,然后是更多更新的版本,并且越来越有可能构建或支持您选择的GCC版本。
顶部或底部的字母顺序不一定是最新版本。 2.9之后,2.10,2.11,2.12,然后有更多的版本,这些版本都是更新的,并且越来越有可能构建或支持你选择的GCC版本。


==== Building GCC: 应该包含系统头的目录不存在 ====
====构建GCC:应该包含系统头的目录不存在====


You might encounter this error when building <tt>mingw32</tt> targets, for example <tt>x86_64-w64-mingw32</tt>. The offending directory that can't be found is <tt>$SYSROOT/mingw/include</tt>. 如果查看sysroot,您当然会意识到不存在这样的文件夹。
在构建<tt>mingw32</tt>目标时可能会遇到此错误,例如<tt>x86_64-w64-mingw32</tt>。 找不到的违规目录是 <tt>$SYSROOT/mingw/include</tt>。 如果查看sysroot,你当然会意识到不存在这样的文件夹。


The solution is simply to create the empty folders:
解决方案只需创建空文件夹:
<source lang="bash">
<source lang="bash">
mkdir -p $SYSROOT/mingw/include
mkdir -p $SYSROOT/mingw/include
第174行: 第174行:
</source>
</source>


这将允许构建继续进行。 发生这种情况的原因是<tt>mingw32</tt>(以及mingw本身)将<tt>包含路径和<tt>库路径配置为<tt>/mingw/INCLUDE</tt>和<tt>/mingw/lib</tt>,而不是默认的<tt>/usr/INCLUDE</tt>和<tt>/usr/lib</tt>。 我无法理解为什么即使这些文件夹中不需要任何东西,构建也会失败,为什么不只是创建它们。
这将允许构建继续进行。 发生这种情况的原因是<tt>mingw32</tt>(以及mingw本身)将<tt>包含路径和<tt>库路径配置为<tt>/mingw/INCLUDE</tt>和<tt>/mingw/lib</tt>,而不是默认的<tt>/usr/INCLUDE</tt>和<tt>/usr/lib</tt>。 即使这些文件夹中不需要任何东西,为什么还会构建失败,为什么不只是创建它们就可以了,我也不明白。


=== GCC libsanitizer未能生成 ===
=== GCC libsanitizer无法构建 ===
有时GCC无法构建libsanitizer,如果发生这种情况,请在configure命令中追加<tt>--disable libsanitizer</tt><br>
有时,GCC无法构建libsanitizer,如果发生这种情况,请在configure命令中附加<tt>--disable-libsanitizer</tt><br>
这仅适用于构建托管编译器。
这仅用于构建托管编译器。


== 更高级 ==
== 更进一步 ==
在相当长的一段时间内,使用这个简单的交叉编译器就足够了,但在某些时候,您会希望编译器自动包含您自己的系统头和库。为您自己的操作系统构建[[OS-Specific Toolchain | OS-Specific Toolchain]]就是一条出路。
在相当长的一段时间内,使用这个简单的交叉编译器就足够了,但在某些时候,你会希望编译器自动包含你自制系统头和库。 为你自制操作系统构建[[OS Specific Toolchain|特定于操作系统的工具链]]是从这里开始的。


== 另见 ==
== 另见 ==
=== 文章 ===
=== 文章 ===
*[[Cross-Compiler Successful Builds]] - combinations of GCC and Binutils which have been shown to work with this tutorial by OSDev.org members.
*[[Cross-Compiler Successful Builds]] - Ossev.org成员已证明可以与本教程一起使用的GCC和Binutils的组合。
*[[Target Triplet]] - on target triplets and their use
*[[Target Triplet]] - Target Triplet及其应用
*[[OS Specific Toolchain]] - going a step further and adding your own target.
*[[OS Specific Toolchain]] - 更进一步,添加你自己的目标。
*[[LLVM Cross-Compiler]] - some compilers make things much easier.
*[[LLVM Cross-Compiler]] - 一些编译器使事情变得容易得多。
*[[Canadian Cross]] - making things yet more complicated.
*[[Canadian Cross]] - 让事情变得更加复杂。


=== 外部链接 ===
===外部链接===
*http://kegel.com/crosstool has a popular example of a script that automatically downloads, patches, and builds binutils, gcc, and glibc for known platforms.
*http://kegel.com/crosstool 有一个很流行的脚本示例,可以为已知平台自动下载、打补丁和构建binutil、GCC和glibc。
*http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html - Summary of the support functions you get when you link with libgcc.
*http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html - 与libgcc链接时获得的支持功能摘要
*http://forums.gentoo.org/viewtopic.php?t=66125 - Compiling Windows applications under Linux
*http://forums.gentoo.org/viewtopic.php?t=66125 - 在Linux下编译Windows应用程序
*http://www.libsdl.org/extras/win32/cross/README.txt - dito
*http://www.libsdl.org/extras/win32/cross/README.txt - Dito
*https://github.com/travisg/toolchains - Another script for building simple cross compilers
*https://github.com/travisg/toolchains - 另一个用于构建简单交叉编译器的脚本
*https://www.youtube.com/watch?v=aESwsmnA7Ec - A walkthrough of how to build a cross-compiler using Cygwin on Windows.
*https://www.youtube.com/watch?v=aESwsmnA7Ec - 介绍如何在Windows上使用Cygwin构建交叉编译器的演练。
*https://github.com/Cheapskate01/Cross-Compiler-Build-Script - A dead-simple script that Binutils and Gcc for you.
*https://github.com/Cheapskate01/Cross-Compiler-Build-Script - 一个非常简单的Binutils和GCC脚本。


[[Category:Compilers]]
[[Category:Compilers]]
第204行: 第204行:
[[de:Cross-Compiler]]
[[de:Cross-Compiler]]


=== Prebuilt Toolchains ===
=== 预先构建的工具链 ===
These were built by people in the OSdev community for their own building needs and shared at will, without guaranteeing any support or that it will even work on your setup. YMMV.
这些都是由OSdev社区中的人根据自己的构建需求构建的,并且可以随意共享,而不保证任何支持,或者它甚至可以在你的工作直接使用。因个人而异请自行考虑使用。


'''Latests versions for Linux (many arch)'''
'''Linux的最新版本(许多是ARCH的)'''


* [https://www.kernel.org/pub/tools/crosstool/ kernel.org various hosts/targets]
* [https://www.kernel.org/pub/tools/crosstool/ kernel.org中的各种主机/目标]


'''For Linux i686 host'''
“适用于Linux i686主机”
* [https://drive.google.com/open?id=1zcFAmxi7mtOwhMaKE36IsjLRB0uEv17p aarch64-elf 9.3.0 target]
* [https://drive.google.com/open?id=1zcFAmxi7mtOwhMaKE36IsjLRB0uEv17p aarch64-elf 9.3.0 target]
* [https://drive.google.com/open?id=1uEFrOJPxy13vxWCy-5IbxCJAs5TRdtTE arm-eabi 9.3.0 target]
* [https://drive.google.com/open?id=1uEFrOJPxy13vxWCy-5IbxCJAs5TRdtTE arm-eabi 9.3.0 target]
第227行: 第227行:
* [https://drive.google.com/open?id=1cqk9RzY3QXQuaS-YdIWtCECKL81pcsv- xtensa-elf 9.3.0 target]
* [https://drive.google.com/open?id=1cqk9RzY3QXQuaS-YdIWtCECKL81pcsv- xtensa-elf 9.3.0 target]


'''For Linux x86_64 host'''
'''对于Linux x86_64主机'''


* [https://drive.google.com/file/d/0Bw6lG3Ej2746STJaM2dNbC05elE/view?usp=sharing i386-elf & i686-elf 7.1.0 target uploaded by TheAlmostGenius]
* [https://drive.google.com/file/d/0Bw6lG3Ej2746STJaM2dNbC05elE/view?usp=sharing i386-elf & i686-elf 7.1.0 target uploaded by TheAlmostGenius]
第245行: 第245行:
* [https://newos.org/toolchains/sparc-elf-7.5.0-Linux-x86_64.tar.xz sparc-elf 7.5.0 target]
* [https://newos.org/toolchains/sparc-elf-7.5.0-Linux-x86_64.tar.xz sparc-elf 7.5.0 target]


The packages from phillid.tk below have been shrunk to about 10 MiB for each pair of packages (GCC &amp; Binutils).
下面来自phillid.tk的软件包已缩小到每对GCC和Binutils软件包约10 MiB。
Please note that this has been achieved by enabling only the C front-end for GCC.
请注意,这是通过只为GCC启用C前端实现的。
If you're going to write your OS in any language but C or Assembly, these packages aren't for you.
如果你打算用C或汇编语言以外的任何语言来编写操作系统,这些软件包不适合你。
These are actually Pacman packages, but untarring them to / and rm-ing /.MTREE and other clutter dotfiles contained in the package will work the same.
这些实际上是Pacman包,但是将它们不加任何限制到 / 和 /rm-ing /.MTREE和包中包含的其他杂乱无章的“.”文件将工作相同。


'''For Windows host'''
'''适用于Windows主机'''
* [https://drive.google.com/file/d/0B85K_c7mx3QjUnZuaFRPWlBIcXM/edit?usp=sharing i686-elf 4.8.2 target]
* [https://drive.google.com/file/d/0B85K_c7mx3QjUnZuaFRPWlBIcXM/edit?usp=sharing i686-elf 4.8.2 target]
* [https://mega.co.nz/#F!bBxA3SKJ!TDL4i1NjaZKd4YMo9p2U7g x86_64-elf 5.1.0 target]
* [https://mega.co.nz/#F!bBxA3SKJ!TDL4i1NjaZKd4YMo9p2U7g x86_64-elf 5.1.0 target]
* [https://github.com/lordmilko/i686-elf-tools i686-/x86_64-elf 7.1.0 target + GDB]
* [https://github.com/lordmilko/i686-elf-tools i686-/x86_64-elf 7.1.0 target + GDB]


'''For Windows Subsystem for Linux (Beta) host'''
'''适用于Windows Subsystem for Linux(Beta)主机'''
* [http://www.bin-os.com/i686-elf-6.1.0.tar.gz i686-elf 6.1.0 target] (extracts to a directory called "cross", don't forget to install 'make' - I would recommend "apt-get install build-essential" to also add additional useful tools)
* [http://www.bin-os.com/i686-elf-6.1.0.tar.gz i686-elf 6.1.0 target] (extracts to a directory called "cross", don't forget to install 'make' - I would recommend "apt-get install build-essential" to also add additional useful tools)


'''For macOS host'''
'''适用于macOS主机'''


x86_64-elf [https://formulae.brew.sh/formula/x86_64-elf-binutils binutils] and [https://formulae.brew.sh/formula/x86_64-elf-gcc gcc] (canonical target name x86_64-pc-elf) can be installed from [https://brew.sh homebrew]:
x86_64-ELF[https://formulae.brew.sh/formula/x86_64-elf-binutils binutils][https://formulae.brew.sh/formula/x86_64-elf-gcc GCC](规范目标名称x86_64-PC-ELF)可以从[https://brew.sh HOMEBREW]安装:
<pre>
<pre>
$ brew install x86_64-elf-gcc
$ brew install x86_64-elf-gcc
</pre>
</pre>
i686-elf toolchain is also [https://formulae.brew.sh/formula/i686-elf-gcc available] in homebrew.
i686-elf工具链也在homebrew[https://formulae.brew.sh/formula/i686-elf-gcc 可用]


'''ARM prebuilt toolchains for multiple host platforms'''
'''针对多主机平台的ARM预构建工具链'''


ARM provides it's own prebuilt toolchain based upon GNU utilities for development targeting ARM systems.
ARM提供了它自制的基于GNU实用程序的预构建工具链,用于针对ARM系统进行开发。


* [https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads GNU ARM Embedded Toolchain]
* [https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads GNU ARM Embedded Toolchain]


'''Docker image'''
'''Docker映像'''
* [https://hub.docker.com/r/joshwyant/gcc-cross/ i686-elf 8.1.0 target]
* [https://hub.docker.com/r/joshwyant/gcc-cross/ i686-elf 8.1.0 target]

2022年2月14日 (一) 05:43的版本

本页面或章节指其读者或编者使用人称 , 我的, 我们 或者 我们的。 用encyclopedic百科全书式的语言风格进行编辑

难度等级
Difficulty 1.png
初学者

本教程重点介绍为开发自制操作系统创建所需的GCC交叉编译器。(译者注:本文中“自己的、自制的”都是说目标操作操作) 我们在这里构建的编译器有一个一般目标(i686-ELF),交叉编译器允许你的编译结果脱离当前操作系统,这意味着不会使用主机操作系统(Host OS)的引用头或库。 你 需要使用交叉编译器来进行操作系统开发,否则可能会发生很多意想不到的事情,因为一般编译器默认会假设你的代码应该在你的当前主机操作系统上运行。

导言

简单来说,交叉编译器是指在平台A(Host主机)上运行,但为平台B(Traget目标)生成可执行文件的编译器。 这两个平台可能 (但不一定) 在CPU、操作系统以及可执行格式方面有所不同。 在我们的例子中,主机平台是你当前的操作系统,目标平台是你即将制作的操作系统。 重要的是要认识到,这两个平台是不同的;你正在开发的操作系统总是不同于你当前使用的操作系统。 这就是为什么我们需要首先构建一个交叉编译器,否则你肯定会遇到麻烦。

为什么需要交叉编译器

正文: Why do I need a Cross Compiler?

除非是在自制的操作系统上进行开发,否则你需要使用交叉编译器。 编译器必须知道正确的目标平台 (CPU,操作系统),否则你将遇到麻烦。 如果你使用系统附带的编译器,那么编译器将不会知道它正在完全编译其他平台的内容。 一些其它教程会建议使用你的系统已有编译器,并将许多特殊的选项传递给编译器。 这肯定会在将来给你带来很多问题,正确的解决方案应该是构建一个交叉编译器。 如果你已经尝试在不使用交叉编译器的情况下创建操作系统,请阅读文章为什么我需要交叉编译器?

选择哪个编译器版本

正文: 构建GCC

推荐使用最新的GCC,因为它是最新和最好的版本。(译者注:这里指的是用什么编译器和源代码编译出新的‘交叉编译器’) 例如,使用GCC 4.6.3构建GCC 4.8.0交叉编译器可能会遇到麻烦。 如果你的系统编译器没有使用最新的主要GCC版本,我们建议你 构建最新的GCC作为你的系统编译器

你也可以使用旧版本,因为它们通常相当好。 如果你的本地系统编译器不是太旧(至少是GCC 4.6.0),你可能希望省去麻烦,只为你的交叉编译器选择非最新的版本(例如,如果你的系统编译器是4.6.1,则为选4.6.3为交叉编译器源代码版本)。

你可以通过调用以下代码查看你当前的编译器版本:

gcc --version

你可以使用较旧的GCC主版本来构建较新的GCC主版本的交叉编译器。 例如,GCC 4.7.3也许能够构建GCC 4.8.0版的交叉编译器。 但是,如果你想为交叉编译器使用最新最好的GCC版本,我们建议你首先将 启动最新GCC 作为系统编译器。 使用OS X 10.7或更早版本的个人可能需要即构建系统GCC(输出本机Mach-O),也要升级本地LLVM/Clang安装。 10.8及以上版本的用户应从苹果开发者网站安装命令行工具,并使用Clang交叉编译GCC。

选择哪个binutils版本

正文: Cross-Compiler Successful Builds

我们建议你使用最新最好的Binutils发行版。 然而,请注意,并不是所有GCC和Binutils的组合都有效。 如果遇到麻烦,请使用与所需编译器版本大致同时发布的Binutils。 你可能至少需要Binutils 2.22,或者最好是最新的2.23.2版本。 你在当前操作系统上安装的Binutils版本并不重要。 你可以通过以下命令找到binutils版本:

ld --version

决定目标平台

正文: Target Triplet

你应该已经明确知道自己的目标平台了。 如果你正在学习Bare Bones教程,那么你应该是希望为i686 elf构建一个交叉编译器。

注意arm-none-eabi-gcc

在Debiab/Ubuntu上的apt-get中有预构建的包gcc-arm-none-eabi,但是你不应该使用它,因为它既不包含libgcc.a,也不包含像stdint.h这样的独立的C头文件。
相反,你应该自己用arm-none-eabi作为$TARGET来构建它。

为构建做准备

难度等级
Difficulty 1.png
初学者


GNU编译器集合是一个具有依赖关系的高级软件。 为了构建GCC,你需要以下内容:

  • 类Unix的环境(Windows用户可以使用Linux或Cygwin的Windows子系统)
  • 足够的内存和硬盘空间 (视情况而定,256 MiB不够)。
  • GCC(有的待替换发行版)或其他system C编译器
  • G++(如果构建GCC的版本>=4.8.0),或其他system C++编译器
  • Make
  • Bison
  • Flex
  • GMP
  • MPFR
  • MPC
  • Texinfo
  • ISL (optional)
  • CLooG (optional)

安装依赖项

↓ Dependency / OS → 源代码 Debian (Ubuntu, Mint, WSL, ...) Gentoo Fedora Cygwin OpenBSD Arch
如何安装 Normally sudo apt install foo sudo emerge --ask foo sudo dnf install foo Cygwin GUI setup doas pkg_add foo pacman -Syu foo
Compiler N/A build-essential sys-devel/gcc gcc gcc-c++ mingw64-x86_64-gcc-g++ / mingw64-i686-gcc-g++ Preinstalled base-devel
Make N/A build-essential sys-devel/make make make Preinstalled base-devel
Bison [1] bison sys-devel/bison bison bison ? base-devel
Flex [2] flex sys-devel/flex flex flex ? base-devel
GMP [3] libgmp3-dev dev-libs/gmp gmp-devel libgmp-devel gmp gmp
MPC [4] libmpc-dev dev-libs/mpc libmpc-devel libmpc-devel libmpc libmpc
MPFR [5] libmpfr-dev dev-libs/mpfr mpfr-devel libmpfr-devel mpfr mpfr
Texinfo [6] texinfo sys-apps/texinfo texinfo texinfo texinfo base-devel
CLooG (Optional) CLooG libcloog-isl-dev dev-libs/cloog cloog-devel libcloog-isl-devel N/A N/A
ISL (Optional) [7] libisl-dev dev-libs/isl isl-devel libisl-devel N/A N/A

你需要安装Texinfo来构建Binutils。 你需要安装GMP、MPC和MPFR来构建GCC。 GCC可以选择使用ClooG和isl库。

例如,你可以通过运行shell命令在Debian上安装 libgmp3-dev: sudo apt install libgmp3-dev

注意:第5版。已知Texinfo的x(或更高版本)与当前的Binutils 2.23.2版本(及更早版本)不兼容。 你可以使用makeinfo--version检查当前版本。 如果你的版本太新,并且在构建过程中遇到问题,则需要使用Binutils 2.24版本 (或更新版本) 或安装旧版本的Texinfo - 也许是通过从源代码上构建 - 并在Binutils构建前后将其添加到PATH

注意: ISL的版本0.13 (或更高版本) 与当前的CLooG 0.18.1版本 (及更早版本) 不兼容。 使用ISL的0.12.2版本,否则生成肯定会失败。

下载源代码

将所需的源代码下载到合适的目录中,例如 $HOME/src:

注意: 使用的版本控制方案是每个句点分开一个完整的数字,即 Binutils 2.20.0比2.9.0更新。 如果查看按字母数字排序的tarball列表时,可能没有用此版本控制方案(相当常见的),这可能会让你感到困惑: 有时列表底部的文件不是最新版本! 获取最新版本的一个简单方法是按上次修改的日期排序并滚动到底部。

Linux用户构建系统编译器

你的发行版可能会发布自己补丁包的GCC和Binutils,这些修补的GCC和Binutils才可以在你的特定Linux发行版上工作。 你应该能够使用上述源代码构建一个工作的交叉编译器,但是你可能无法用源代码为当前的Linux发行版构建一个新的系统编译器。 在这种情况下,请尝试较新的GCC版本或获取打了补丁的源代码。

Gentoo用户

Gentoo提供crossdev来建立交叉开发工具链:

   emerge -av crossdev
   crossdev --help
   PORTDIR_OVERLAY="/usr/local/crossdev" crossdev --stage1 --binutils <binutils-version> --gcc <gcc-version> --target <target>

这将把GCC交叉编译器安装到一个"slot"中,即与现有的编译器版本一起安装。 你可以通过这种方式安装多个交叉编译器,只需更改目标名称即可。 它的缺点是,它还将引入gentoo补丁,并传递与官方GCC Cross-Compiler设置不同的额外配置选项,它们的行为可能会有所不同。

编译成功后,可以通过<target>-GCC调用你的交叉编译器。 如果需要,你还可以使用gcc-config在编译器版本之间切换。 不要用交叉编译器替换系统编译器。 包管理器还会在更新可用时立即提出建议。

你可以通过调用 “crossdev --clean <target>” 来卸载交叉编译器。 阅读交叉开发文档以获取更多信息。

请注意,binutils和GCC的版本号是Gentoo package versions, 即 "官方" (GNU) 版本可能有一个后缀,用于解决Gentoo维护者提供的其他补丁集。 (例如,--binutils 2.24-r3--gcc 4.8.3是撰写本文时最新的稳定包对。) 你可以省略版本号以使用可用的最新软件包。

Portage使用Overlay来存储不属于原始软件包管理的软件包。 Crossdev需要一个Overlay,在构建它们之前可以在其中存储其binutils和gcc包。 你可以正确配置一个,也可以使用PORTDIR_OVERLAY指向它应该保存其包管理器文件的位置。 使用PORTDIR_OVERLAY现有的overlay不是一个好主意,但是到那时你应该知道你是曾经是如何亲自设置它们的,以及如何正确地进行设置。 参考 [8].

MacOS用户

macOS用户需要替换libiconv,因为系统libiconv已经严重过时。 macOS用户可以通过访问网站或直接访问主FTP镜像。 否则,在OS X 10.4和10.5上编译GCC 4.3或更高版本时,可能会出现与libiconv相关的未解决符号错误。

安装新版本(自己编译或使用MacPorts)并添加 --with-libiconv-prefix=/opt/local (如果你自己编译,则为 /usr/local) 到GCC的 ./configure 行。 或者,你可以将libiconv源代码放置到GCC-x.y.z/libiconv,它将作为GCC编译过程的一部分进行编译。 (此技巧也适用于MPFR,GMP和MPC)。

Binutils和GCC的makefile使用$(CC)变量来调用编译器。 在OS X上,默认解析为gcc,实际是 clang. 在OSX10.8之前,Xcode的命令行工具包附带的Clang无法构建一个正常工作的GCC。 运行OS X 10.7或以下版本的用户可能需要从 Homebrew 或从Apple网站上的某个地方查找并安装GCC。 你可以尝试使用预装在某些macOS版本上的旧GCC。

# This is only necessary for OS X users running 10.7 or below.
export CC=/usr/bin/gcc-4.2
export CXX=/usr/bin/g++-4.2
export CPP=/usr/bin/cpp-4.2
export LD=/usr/bin/gcc-4.2

一旦编译并安装了交叉编译器,你就需要取消设置这些导出。

Lion用户注意: 如果你在Lion(或更高版本)上,很可能你没有“真正的”GCC,因为苹果从Xcode软件包中删除了它,但你仍然可以安装它。 你可以通过Homebrew或通过从源代码编译来实现,a StackExchange Answer对这两种方法都有很好的描述。

Maverick用户注意: 可以使用Xcode 5.1.1构建binutils-2.24和gcc-4.8.3(可能的其他版本)。 请注意,使用LLVM构建GCC不是官方支持的,可能会导致有趣的错误,如果你愿意冒这个风险并想节省时间构建出host-gcc只是为了编译一个cross-gcc,请遵循以下内容。 用 MacPorts 安装GMP、MPFR、Mpc。

sudo port install gmp mpfr libmpc
../binutils-2.24/configure --prefix=$PREFIX \
--target=$TARGET \
--enable-interwork --enable-multilib \
--disable-nls --disable-werror
../gcc-4.8.3/configure --prefix=$PREFIX \
--target=$TARGET \
--disable-nls \
--enable-languages=c,c++ --without-headers \
--enable-interwork --enable-multilib \
--with-gmp=/usr --with-mpc=/opt/local --with-mpfr=/opt/local

注意: port的GMP存在问题,因此使用来自/usr的OS X版本。

Windows用户

Windows用户需要设置类Unix的环境,如MinGWCygwin。 也许值得先研究研究Linux等系统,看看它们是否符合你的需求,因为你通常在操作系统开发中使用许多类Unix的工具,而从类Unix的操作系统来看,这要容易得多。 如果你刚刚安装了基本的Cygwin软件包,你必须再次执行setup.exe并安装以下软件包: GCC, G++, Make, Flex, Bison, Diffutils, libintl-devel, libgmp-devel, libmpfr-devel, libmpc-devel, Texinfo

MinGW MSYS是一种选择,由于它解决了本机Windows API而不是POSIX仿真层,因此工具链速度稍快。 一些软件包无法在MSYS下正确构建,因为它们不是为Windows设计的。 就本教程而言,除非另有说明,否则适用于Cygwin的所有内容也适用于MSYS。 确保安装C和C++编译器以及MSYS基本系统。

与Windows 10周年更新一起发布的“Windows Linux子系统(Beta版)”也是使用交叉编译器的一个选项。(使用GCC 6.1.0和Binutils 2.27于2016年8月8日进行测试)尽管处于测试状态,该交叉编译器运行速度相当快,但可能不是理想的永久性开发平台。

Cygwin注意: Cygwin在其bash %PATH%中包含你的Windows %PATH% 如果你以前使用过DJGPP,这可能会导致混淆,例如在Cygwin bash命令行上调用GCC仍会调用DJGPP编译器。 卸载DJGPP后,应删除DJGPP环境变量,并从 %PATH%中清除C:\djgpp条目(或其安装位置)。 同样,在系统路径变量中混淆构建环境可能是一个坏主意。

MinGW 注意: 有关构建跨工具链的一些特定于MinGW的信息可以在MinGW主页上的托管的交叉编译器操作页面上找到

Windows Subsystem for Linux (Beta) 注意: 你不能让交叉编译器位于/mnt/c/(或/mnt/“x”)区域,因为尝试在那里编译交叉编译器会产生错误,而构建到$HOME/opt/cross则可以完美地工作。 此问题已使用Windows Update KB3176929修复

OpenBSD用户

OpenBSD用户可能需要从port安装“gcc”包,因为基本系统的gcc非常过时。 如果你想构建GCC,请尝试使用port对应的版本,而不是最新可用的版本,并将所有来自port的补丁应用到你的版本中。 另外,如果在编译LT0插件期间构建失败,则临时解决方案是在构建GCC的配置阶段通过添加 --disable-lto 来完全禁用LTO

构建

我们计划构建一个在你的主机上运行的工具集,可以将源代码转换为目标系统的目标文件。

你需要决定在哪里安装你的新编译器。 将其安装到系统目录中的做法既危险又糟糕。 你还需要决定是应该全局安装新编译器,还是只为个人单用户安装新编译器。 如果你只想为自己安装 (推荐),则通常比较好的主意将其安装到 $ HOME/opt/cross 中。 如果你想在全局安装它,则最好通常将其安装到/usr/local/cross

请注意,我们最好在源代码目录树之外构建所有内容。 有些软件包仅支持外部构建,有些仅支持内部建筑,有些则两者兼而有之 (但可能无法对构建过程进行广泛的检查)。 在源目录树中构建GCC会失败得很惨,至少对于旧版本来说是如此。

准备

export PREFIX="$HOME/opt/cross"
export TARGET=i686-elf
export PATH="$PREFIX/bin:$PATH"

我们将安装前缀(PREFIX)添加到当前shell会话的 PATH 中。 这确保了一旦我们构建了新的binutil,编译器构建就能够检测它们。

前缀将配置构建过程,以便你的交叉编译器环境的所有文件都以$HOME/opt/cross开头。 你可以将该前缀更改为你喜欢的任何内容 (例如,/opt/cross或 $HOME/cross 都可以)。 如果你具有管理员权限,并且希望所有用户都可以使用交叉编译器工具链,则可以将其安装到/usr/local前缀中 - 或者,如果你愿意更改系统配置,使此目录位于所有用户的搜索路径中,也可以使用/usr/local/cross前缀。 从技术上讲,你甚至可以直接安装到/usr,这样你的交叉编译器将与你的系统编译器一起驻留,但由于各种原因,不建议你这样做 (例如,如果目标错误,可能会覆盖系统编译器,或者与系统的包管理发生冲突)。

Binutils

cd $HOME/src

mkdir build-binutils
cd build-binutils
../binutils-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
make
make install

这将编译binutils (汇编程序,反汇编程序和其他各种有用的东西),它们可在你的系统上运行,但以$TARGET指定的格式处理代码。

--disable-nls告诉binutils不要包含本机语言支持。 这基本上是可选的,但可以减少依赖性和编译时间。 这也会影响诊断结果的英文,当你提出问题时,论坛 上的人们会理解。;-) (译者注:没有作者Get意思)

--with-sysroot告诉binutils在交叉编译器中启用sysroot支持,方法是将其指向默认的空目录。 默认情况下,因为没有很好的技术原因,链接器拒绝使用sysroot,而GCC能够在运行时处理这两种情况。 这将在以后有用。

GCC

另请参阅配置GCC的官方说明

现在,你可以开始构建 GCC了。

cd $HOME/src

# The $PREFIX/bin dir _must_ be in the PATH. We did that above.
which -- $TARGET-as || echo $TARGET-as is not in the PATH

mkdir build-gcc
cd build-gcc
../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc

我们构建libgcc,这是一个低级支持库,编译器希望它在编译时可用。 针对libgcc的链接提供整数、浮点、小数、堆栈展开(用于异常处理)和其他支持功能。 请注意,我们这里没有简单地运行 make && make install,因为这会构建太多的方式,并不是gcc的所有组件都针对你未完成的操作系统已准备好。

--disable-nls 与上面的binutils相同。

--without-headers告诉GCC不要为目标依赖任何存在的C库(标准库或运行时库)。

--enable-languages 告诉 GCC 不要编译它支持的所有其他语言前端,而只能编译C (以及可选的C++)。

构建交叉编译器需要一段时间。

如果你正在构建x86-64的交叉编译器,则可能需要考虑构建不带“red zone”的Libgcc:Libgcc_Without_red_zone

使用新的编译器

现在你有了一个“裸”交叉编译器。 它还不能访问C库或C运行时,因此你不能使用任何标准的包含语句或创建可运行的二进制文件。 但是编译你将马上要制作的内核已经足够了。 你的工具集位于$HOME/opt/cross(或你设置的$PREFIX中)。 例如,你将GCC可执行文件安装为$HOME/opt/cross/bin/$TARGET-gcc,它将为你的目标创建程序。

你现在可以通过调用类似的东西来运行你的新编译器:

$HOME/opt/cross/bin/$TARGET-gcc --version

请注意,此编译器“无法”编译普通C程序。 每当你想要#include包含任何标准标头时,交叉编译器都会产生错误(除了少数实际上独立于平台并由编译器本身生成的标头)。 这是对于操作系统开发是非常必要的-你还没有目标系统的标准库!

C标准定义了两种不同的执行环境——“独立freestanding”和“托管hosted”。 虽然对于普通的应用程序程序员来说,这个定义可能相当模糊,但是当你进行操作系统开发时,它是相当清晰的: 内核执行是 “独立的”,你在用户空间中做的一切都是 “托管的”。 “独立”环境只需要提供C库的一个子集:float.h、 iso646.h、 limits.h、 stdalign.h、 stdarg.h、 stdbool.h、 stddef.h, stdint.h和stdnoreturn.h(从C11开始)。 所有这些文件都“仅仅”由typedef s和#define s 组成,因此你可以在看不到一个.c文件的情况下使用它们。

要简单地通过调用 $TARGET-gcc 来使用你的新编译器,请通过键入将 $ HOME/opt/cross/bin 添加到你的 $PATH 中:

export PATH="$HOME/opt/cross/bin:$PATH"

此命令将把新编译器添加到此shell会话的路径中。 如果你希望永久使用它,请将path命令添加到你的~/.profile配置shell脚本或类似脚本中。 有关更多信息,请参阅你的shell文档。

如果是你是从Bare Bones教程来到这里,那么现在你可以再使用新的交叉编译器来完成它,实现一个新的变体。 如果你开始是构建了一个新的GCC版本作为系统编译器,并使用它来构建出了交叉编译器,那么你现在可以安全地卸载那个系统编译器,除非你希望继续使用它。

故障排除

一般来说,这里要验证的仅是你仔细阅读了说明,并准确键入了命令。 不要跳过说明。 如果你使用新的shell实例,如果你没有将其添加到shell配置文件中,则必须再次设置PATH变量。 如果编译过程似乎真的搞砸了,请键入make distclean,然后重新开始make过程。 确保你的解压软件不会更改换行符。

ld: 找不到 -lgcc

你通过-lgcc开关将GCC低级运行库链接到可执行文件中,但忘记了构建和正确安装库
如果在安装libgcc时没有收到任何警告或错误,但仍然存在问题,则可以将库复制到项目中并将其用-L. -lgcc
链接 libgcc位于 $PREFIX/lib/gcc/$TARGET/<gcc-version>/libgcc.a。

Binutils2.9

顶部或底部的字母顺序不一定是最新版本。 2.9之后,2.10,2.11,2.12,然后有更多的版本,这些版本都是更新的,并且越来越有可能构建或支持你选择的GCC版本。

构建GCC:应该包含系统头的目录不存在

在构建mingw32目标时可能会遇到此错误,例如x86_64-w64-mingw32。 找不到的违规目录是 $SYSROOT/mingw/include。 如果查看sysroot,你当然会意识到不存在这样的文件夹。

解决方案只需创建空文件夹:

mkdir -p $SYSROOT/mingw/include
mkdir -p $SYSROOT/mingw/lib

这将允许构建继续进行。 发生这种情况的原因是mingw32(以及mingw本身)将包含路径和库路径配置为/mingw/INCLUDE/mingw/lib,而不是默认的/usr/INCLUDE/usr/lib。 即使这些文件夹中不需要任何东西,为什么还会构建失败,为什么不只是创建它们就可以了,我也不明白。

GCC libsanitizer无法构建

有时,GCC无法构建libsanitizer,如果发生这种情况,请在configure命令中附加--disable-libsanitizer
这仅用于构建托管编译器。

更进一步

在相当长的一段时间内,使用这个简单的交叉编译器就足够了,但在某些时候,你会希望编译器自动包含你自制系统头和库。 为你自制操作系统构建特定于操作系统的工具链是从这里开始的。

另见

文章

外部链接

de:Cross-Compiler

预先构建的工具链

这些都是由OSdev社区中的人根据自己的构建需求构建的,并且可以随意共享,而不保证任何支持,或者它甚至可以在你的工作直接使用。因个人而异请自行考虑使用。

Linux的最新版本(许多是ARCH的)

“适用于Linux i686主机”

对于Linux x86_64主机

下面来自phillid.tk的软件包已缩小到每对GCC和Binutils软件包约10 MiB。 请注意,这是通过只为GCC启用C前端实现的。 如果你打算用C或汇编语言以外的任何语言来编写操作系统,这些软件包不适合你。 这些实际上是Pacman包,但是将它们不加任何限制到 / 和 /rm-ing /.MTREE和包中包含的其他杂乱无章的“.”文件将工作相同。

适用于Windows主机

适用于Windows Subsystem for Linux(Beta)主机

  • i686-elf 6.1.0 target (extracts to a directory called "cross", don't forget to install 'make' - I would recommend "apt-get install build-essential" to also add additional useful tools)

适用于macOS主机

x86_64-ELFbinutilsGCC(规范目标名称x86_64-PC-ELF)可以从HOMEBREW安装:

$ brew install x86_64-elf-gcc

i686-elf工具链也在homebrew可用

针对多主机平台的ARM预构建工具链

ARM提供了它自制的基于GNU实用程序的预构建工具链,用于针对ARM系统进行开发。

Docker映像