原文链接:https://wiki.osdev.org/GCC_Cross-Compiler
主页:https://blog.csdn.net/qq_37422196/article/details/122591214
下面的链接如果指向原网站的话,大概是还没有翻译
在赶了在赶了……
难度等级:入门
本教程的重点是为你自己的操作系统创建GCC交叉编译器。我们在这里构建的这个编译器会生成统一的目标架构(i686-elf),它让你可以编译时无视当前的操作系统,这意味着不会使用你的主机操作系统的任何头文件和库。你需要一个用于操作系统开发的交叉编译器,否则会发生很多意想不到的事情,因为编译器假定你的代码在你的主机操作系统上运行
介绍
一般来说,交叉编译器是在平台 A(主机平台)上运行,但为平台 B(目标平台)生成可执行文件的编译器。这两个平台可能(但不一定)在CPU、操作系统和/或可执行文件格式方面有所不同。在我们的例子中,主机平台是你当前的操作系统,目标平台是你即将制作的操作系统。重要的是要意识到这两个平台并不相同。你正在开发的操作系统总是与你当前使用的操作系统不同。这就是为什么我们需要先构建一个交叉编译器,否则你肯定会遇到麻烦
为什么需要交叉编译器
主条目:为什么需要交叉编译器?
除非你在自己的操作系统上进行开发,否则你需要使用交叉编译器。编译器必须知道正确的目标平台(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版本
主条目:交叉编译器的成功构建
我们建议你使用最新最好的binutils版本。但是请注意,并非GCC和binutils的所有组合都有效。如果遇到麻烦,请使用与所需编译器版本大致同时发布的binutils。你可能至少需要binutils 2.22,或者最好是最新的2.23.2版本。你在当前操作系统上安装的binutils版本无关紧要。你可以通过以下命令找到binutils版本:
ld --version
确定目标平台
主条目:目标三元组
你应该已经知道了你的目标平台了。如果你正在学习Bare Bones教程,你应该为i686-elf
构建一个交叉编译器
关于arm-none-eabi-gcc的注意事项
apt-get上有用于Debiab/Ubuntu的预构建包gcc-arm-none-eabi,但你不应该使用它,因为它既不包含libgcc.a也不包含独立的C头文件,比如stdint.h
相反,你应该让arm-none-eabi
作为$TARGET自己构建它
构建准备
难度等级:入门
GNU编译器集合(GCC)是一个具有依赖关系的高级软件。为了构建GCC,你需要以下内容:
- 类Unix环境(Windows用户可以使用WSL或Cygwin)
- 足够的内存和硬盘空间(视情况而定,256MiB是不够的)
- GCC(你希望替换的现有版本)或其他系统C编译器
- G++(如果构建GCC>=4.8.0的版本),或其他系统C++编译器
- make
- bison
- flex
- GMP
- MPFR
- MPC
- texinfo
- ISL(可选)
- CLooG(可选)
安装依赖
操作系统 | 源码安装 | Debian(Ubuntu, Mint, WSL, …) | Gentoo | Fedora | Cygwin | OpenBSD | Arch |
---|---|---|---|---|---|---|---|
如何安装 | 网址如下 | sudo apt install foo | sudo emerge --ask foo | sudo dnf install foo | Cygwin图形界面中设置 | doas pkg_add foo | pacman -Syu foo |
编译器 | N/A | build-essential | sys-devel/gcc | gcc gcc-c++ | mingw64-x86_64-gcc-g++或mingw64-i686-gcc-g++ | 预装 | base-devel |
make | N/A | build-essential | sys-devel/make | make | make | 预装 | base-devel |
bison | https://ftp.gnu.org/gnu/bison/ | bison | sys-devel/bison | bison | bison | ? | base-devel |
flex | https://github.com/westes/flex/releases | flex | sys-devel/flex | flex | flex | ? | base-devel |
GMP | https://ftp.gnu.org/gnu/gmp/ | libgmp3-dev | dev-libs/gmp | gmp-devel | libgmp-devel | gmp | gmp |
MPC | https://ftp.gnu.org/gnu/mpc/ | libmpc-dev | dev-libs/mpc | libmpc-devel | libmpc-devel | libmpc | libmpc |
MPFR | https://ftp.gnu.org/gnu/mpfr/ | libmpfr-dev | dev-libs/mpfr | mpfr-devel | libmpfr-devel | mpfr | mpfr |
texinfo | https://ftp.gnu.org/gnu/texinfo/ | texinfo | sys-apps/texinfo | texinfo | texinfo | texinfo | base-devel |
CLooG(可选) | CLooG | libcloog-isl-dev | dev-libs/cloog | cloog-devel | libcloog-isl-devel | N/A | N/A |
ISL(可选) | http://isl.gforge.inria.fr/ | libisl-dev | dev-libs/isl | isl-devel | libisl-devel | N/A | N/A |
你需要安装texinfo来构建binutils。你需要安装GMP、MPC和MPFR来构建GCC。可选地,GCC可以调用ClooG和ISL库
例如,在Debian上安装libgmp3-dev
,你可以运行shell命令:sudo apt install libgmp3-dev
注:texinfo的5.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网站或直接访问GNU主镜像来下载所需的binutils版本
- 你可以通过访问GCC网站或直接访问GNU主镜像来下载所需的GCC版本
注:使用的版本控制方案是每个句号分隔一个完整的数字,即binutils 2.20.0比2.9.0更新。如果你还没有遇到这种(非常常见的)版本控制方案,在查看按字母数字排序的tar文件列表时,这可能会令你感到困惑:列表底部的文件不是最新版本!获取最新版本的一种简单方法是按最后修改日期排序并滚动到底部
Linux用户构建系统编译器
你的发行版可能会发布自己修补后的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交叉编译器设置不同的额外配置选项,并且它们的行为可能不同
编译成功后,你可以通过<target>-gcc来调用交叉编译器。如果需要,你还可以使用gcc-config在编译器版本之间切换。不要用交叉编译器替换你的系统编译器。包管理器还将在更新可用时立即提出建议
你可以通过执行crossdev --clean <target>
来卸载交叉编译器。阅读交叉开发文档以获取更多信息
请注意,binutils和gcc的版本号是Gentoo软件包版本,即“官方”(GNU)版本可能有一个后缀,用于处理由Gentoo维护者提供的附加补丁集(例如,–binutils 2.24-r3 --gcc 4.8.3是撰写本文时最新的稳定软件包对)。你可以省略版本号以使用最新的可用软件包
Portage使用叠加层来存储不属于原始包管理的包。Crossdev需要一个叠加层,它可以在构建它们之前存储它的binutils和gcc包。你可以正确配置一个,或者你可以使用PORTDIR_OVERLAY指向它应该保存其包管理器文件的位置。在已有叠加层时使用PORTDIR_OVERLAY并不是一个好主意,但是到那时你应该知道应该更早地亲自设置它们以及如何正确地进行设置的。见https://wiki.gentoo.org/wiki/Custom_repository#Crossdev
macOS用户
macOS用户需要更换libiconv,因为系统libiconv严重过时。macOS用户可以通过访问libiconv网站或直接访问GNU主FTP镜像来下载最新的libiconv版本。否则,在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
。在OS X 10.8之前,Xcode的命令行工具包附带的Clang无法成功构建GCC。运行OS X 10.7或更低版本的用户可能需要从Homebrew或苹果网站上的某个位置查找并安装GCC。你可以尝试使用某些macOS版本上预装的旧GCC
# 仅适用于运行10.7或更低版本的OS X用户
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
编译并安装完交叉编译器后,你需要取消设置这些export。
Lion用户注意事项:如果你使用Lion(或更高版本),你可能没有“真正的”GCC,因为苹果从Xcode包中删除了它,但你仍然可以安装它。你可以通过Homebrew或从源代码编译来完成,两者都在StackExchange的回答中得到了完美的描述。
Maverick用户注意事项:你可以使用Xcode 5.1.1构建binutils-2.24和gcc-4.8.3(其他版本也有可能)。请注意,官方不支持使用LLVM构建GCC,并且可能会导致有意思的错误,如果你愿意冒这个风险并节省构建主机gcc的时间来编译交叉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环境,例如MinGW或Cygwin。你可能得研究一下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周年更新发布的“适用于Linux的Windows子系统(Beta)”也是使用交叉编译器的一个选择(使用GCC 6.1.0和binutils 2.27于2016年8月8日测试)。此交叉编译器运行速度相当快,尽管处于beta状态,但它可能不是理想的永久开发平台
Cygwin注意事项: Cygwin会在其bash$PATH
中包含你的%PATH%
。如果你以前使用过DJGPP,这可能会让你感到困惑,例如在Cygwin bash命令行上调用GCC仍会调用DJGPP编译器。卸载DJGPP后,你应该删除DJGPP环境变量并从%PATH%中清除C:\djgpp
条目(或其他安装它的位置)。同样,在系统PATH变量中混合构建环境可能是个坏主意
MinGW注意事项:一些有关MinGW构建交叉工具链的信息可以在MinGW主页上的“托管交叉编译器操作指南”页面(链接已失效)上找到
适用于Linux的Windows子系统(Beta)注意事项:你不能将交叉编译器放在/mnt/c/(或/mnt/“x”)区域,因为尝试在那里编译交叉编译器会产生错误,而构建到$HOME/opt/cross则完美运行。这已在Windows更新KB3176929中修复
OpenBSD用户
OpenBSD用户可能需要从port安装“gcc”包,因为基本系统的GCC非常过时。如果你想构建GCC,请尝试使用port版本而不是可用的最新版本,并将port中的所有补丁应用到你的构建中。此外,如果在编译lto-plugin期间构建失败,临时解决方案是在构建GCC的配置阶段通过添加--disable-lto
完全禁用LTO
构建
我们构建了一个在你的主机上运行的工具集,可以将源代码转换为目标系统的目标文件
你需要决定在哪里安装新编译器。将其安装到系统目录中是危险的,也是一个非常糟糕的主意。你还需要决定是应该全局安装新编译器还是只为你安装。如果你只想为你自己安装它(推荐),安装到$HOME/opt/cross
通常是一个好主意。如果你想全局安装它,将它安装到/usr/local/cross
通常是一个好主意
请注意,我们在源目录树外构建所有内容,大家普遍认为这是一种好的做法。一些包只支持外部构建,一些只支持内部构建,一些两者都支持(但可能不提供对make的充分检查)。在源目录树中构建GCC失败得很惨,至少对于旧版本来说是这样
准备
export PREFIX="$HOME/opt/cross"
export TARGET=i686-elf
export PATH="$PREFIX/bin:$PATH"
我们将安装目录(PREFIX)添加到当前shell会话的PATH
中。这确保了编译器构建能够在我们构建它们后检测到我们的新binutils
PREFIX将配置构建过程,以让你的交叉编译器环境的所有文件最后都在 $HOME/opt/cross下。你可以将PREFIX更改为你喜欢的任何地方(例如,/opt/cross或$HOME/cross就是两种选择)。如果你有管理员权限并希望让所有用户都可以使用交叉编译器工具链,你可以将它安装到/usr/local中——如果你愿意更改系统配置以使该目录位于所有用户的搜索路径中,也可以安装到/usr/local/cross中。从技术上讲,你甚至可以直接安装到/usr,这样你的交叉编译器将与你的系统编译器放在一起,但出于多种原因不建议这样做(例如,如果TARGET错误,或者与系统的包管理发生冲突,就有可能覆盖你的系统编译器)
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不包括本地语言支持。这基本上是可选的,但减少了依赖性和编译时间。它还让其使用英语报错,这样当你提出问题时,论坛上的人能够理解;-)
–with-sysroot告诉binutils在交叉编译器通过将sysroot指向默认的空目录来启用sysroot。默认情况下,链接器拒绝无缘无故使用sysroot,而gcc能够在运行时处理这两种情况。这将在以后有用
GCC
另请参阅配置gcc的官方说明
现在你可以构建GCC了
cd $HOME/src
# $PREFIX/bin必须在PATH中。我们之前已经设置过了
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构建交叉编译器,你可能需要考虑构建没有“红色区域”的libgcc
使用新编译器
现在你有了一个“裸”的交叉编译器。它还不能访问C库或C运行时,因此你不能使用任何标准包含或创建可运行的二进制文件,但是足够编译你之后制作的内核了。你的工具集位于$HOME/opt/cross(或你将$PREFIX设置的位置)中。例如,你将GCC可执行文件安装到$HOME/opt/cross/bin/$TARGET-gcc,它会为你的目标平台构建程序
你现在可以通过执行类似以下的命令来运行你的新编译器:
$HOME/opt/cross/bin/$TARGET-gcc --version
请注意此编译器无法编译正常的C程序。每当你想要#include任何标准头文件时,交叉编译器都会报错(除了少数实际上与平台无关且由编译器本身生成的部分)。这是完全正确的——你还没有目标系统的标准库!
C标准定义了两种不同的执行环境——“独立”和“托管”。虽然对于一般的应用程序程序员来说,这个定义可能相当模糊;但当你进行操作系统开发时,这非常明确:内核是“独立的”,你在用户空间中所做的一切都是“托管的”。“独立”环境只需要提供C库的一个子集:float.h、iso646.h、limits.h、stdalign.h、stdarg.h、stdbool.h、stddef.h、stdint.h和stdnoreturn.h(截止至C11)。所有这些都“仅”由typedef和#define组成,因此你可以在没有任何.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过程。确保你的un-archiver不会更改换行符
ld: 找不到 -lgcc
你指定要通过-lgcc
开关将GCC低级运行时库链接到可执行文件中,但忘记构建和正确安装库
如果你在安装 libgcc 时没有收到警告或错误,但仍然有问题,你可以将库复制到项目中并通过-L. -lgcc
链接
libgcc 位于 $PREFIX/lib/gcc/$TARGET//libgcc.a
binutils 2.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本身)将INCLUDE_PATH
和LIBRARY_PATH
配置为,可以猜到,/mingw/include
和/mingw/lib
,而不是默认值/usr/include
和/usr/lib
。为什么即使这些文件夹中不需要任何东西,构建也会失败,以及为什么它不只是创建它们,我也不知道
GCC libsanitizer无法构建
有时GCC无法构建libsanitizer,如果发生这种情况,请将--disable-libsanitizer
附加到configure命令
这仅适用于构建托管编译器
进阶
在相当长的一段时间内使用这个简单的交叉编译器就足够了,但在某些时候你会希望编译器自动包含你自己的系统头文件和库。为你自己的操作系统构建一个指定操作系统的工具链是解决方案
相关内容
文章
- 可以使用的交叉编译组合——已被OSDev.org成员证明可以与本教程一起使用的GCC和binutils的组合
- 目标三元组——关于目标三元组及其使用
- 指定操作系统的工具链——更进一步并添加你自己的目标平台
- LLVM交叉编译器——让事情变得更容易的编译器
- 加拿大交叉编译——让事情变得更加复杂
外部链接
- http://kegel.com/crosstool有一个流行的脚本示例,它可以为已知平台自动下载、修补和构建binutils、gcc和glibc
- http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html——链接libgcc时获得的支持功能摘要。
- http://forums.gentoo.org/viewtopic.php?t=66125——在Linux下编译Windows应用程序
- http://www.libsdl.org/extras/win32/cross/README.txt——同上
- https://github.com/travisg/toolchains——另一个用于构建简单交叉编译器的脚本
- https://www.youtube.com/watch?v=aESwsmnA7Ec——如何在Windows上使用Cygwin构建交叉编译器的演示
- https://github.com/Cheapskate01/Cross-Compiler-Build-Script——非常简单的构建binutils和gcc的脚本
构建好的工具链
这些是由OSdev社区中的人们根据自己的构建需求构建的,并且自愿分享,但不保证任何支持,甚至不保证可以在你的设置上运行
懒得复制了,直接看原文