交叉编译gcc源码-将 GCC 构建为 Raspberry-Pi 的交叉编译器

将 GCC 构建为 Raspberry-Pi 的交叉编译器

在本文中,展示如何构建 GCC10 作为 RaspberryPi 的交叉编译器。 交叉编译器是一种在一个操作系统上运行并为另一个操作系统生成可执行文件的编译器。 当您想在强大的计算机上为奇异果派构建库或其他小段代码时,这非常有用。 作为一个实际示例,在本文末尾,我将向您展示如何使用交叉编译器将 GCC 本身构建为原生 RaspberryPi 应用程序。

本文中介绍的方法的优点是您可以使用交叉编译器来构建 RPiZero 和可执行文件。 使用 Debian 官方的 crossbuild-essential-armhf,您只能为 RaspberryPi2 及以上版本构建补码文件。

这篇文章的一部分是我从其他人的帖子中学到的。 以下是我使用过的一些资源:


•	http://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/
•	https://www.raspberrypi.org/documentation/linux/kernel/building.md
•	https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F
•	https://wiki.osdev.org/GCC_Cross-Compiler
•	https://wiki.osdev.org/Building_GCC
•	http://www.ifp.illinois.edu/~nakazato/tips/xgcc.html

从前面的列表中,第一篇文章是最完整的,如果您遵循它,您将获得部分工作的交叉编译器。 公平地说,这篇文章不是为奇异果派写的。 如果您想了解该过程各个步骤的更深入解释,我建议您阅读它。

为了构建和托管交叉编译器,我使用了 Debian 10,并且其他 Linux 发行版上应该也有类似的过程。

首先,确保您的系统已更新并安装了所需的先决条件:

1 sudo apt update
2 sudo apt upgrade
3 sudo apt install build-essential gawk git texinfo bison file wget

Raspbian 附带 GCC8.3.0、Binutils2.31 和 Glibc2.28。 使用与 Raspbian 版本相同的 Glibc 版本构建交叉编译器非常重要。 这将使我们能够与操作系统很好地集成。 如果你来自未来并且阅读了这篇文章,你可以使用以下命令来检查上述软件的版本:

1 gcc --version
2 ld -v
3 ldd --version

这是我在猕猴桃派上看到的:

 1 pi@raspberrypi:~ $ gcc --version
 2 gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
 3 Copyright (C) 2018 Free Software Foundation, Inc.
 4 This is free software; see the source for copying conditions.  There is NO
 5 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 6 
 7 pi@raspberrypi:~ $ ld -v
 8 GNU ld (GNU Binutils for Raspbian) 2.31.1
 9 pi@raspberrypi:~ $ ldd --version
10 ldd (Debian GLIBC 2.28-10+rpi1) 2.28
11 Copyright (C) 2018 Free Software Foundation, Inc.
12 This is free software; see the source for copying conditions.  There is NO
13 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 Written by Roland McGrath and Ulrich Drepper.
15 pi@raspberrypi:~ $

如果您尝试使用更现代的 GCC(例如 9.x 或 10.x)构建 glibc2.28,您将收到很多错误。 最简单的方法是使用 GCC 8.3.0 构建 Glibc,并将其与最新最好的 GCC(当前为 10.1)一起使用。

在接下来的说明中,我假设您在单独的文件夹中执行所有步骤,但您将保持同一终端会话打开,直到完成所有操作。 例如,您可以在家里创建一个工作文件夹:

1 cd ~
2 mkdir gcc_all && cd gcc_all

让我们下载用于构建交叉编译器的软件:

1 wget https://ftpmirror.gnu.org/binutils/binutils-2.31.tar.bz2
2 wget https://ftpmirror.gnu.org/glibc/glibc-2.28.tar.bz2
3 wget https://ftpmirror.gnu.org/gcc/gcc-8.3.0/gcc-8.3.0.tar.gz
4 wget https://ftpmirror.gnu.org/gcc/gcc-10.1.0/gcc-10.1.0.tar.gz
5 git clone --depth=1 https://github.com/raspberrypi/linux

接下来交叉编译gcc源码,提取存档并将其删除:

1 tar xf binutils-2.31.tar.bz2
2 tar xf glibc-2.28.tar.bz2
3 tar xf gcc-8.3.0.tar.gz
4 tar xf gcc-10.1.0.tar.gz
5 rm *.tar.*

GCC 还需要一些先决条件,我们可以在源文件夹中下载:

1 cd gcc-8.3.0
2 contrib/download_prerequisites
3 rm *.tar.*
4 cd ..
5 cd gcc-10.1.0
6 contrib/download_prerequisites
7 rm *.tar.*
8 cd ..

接下来,创建一个文件夹,放置交叉编译器,并将其添加到路径中:

1 cd ~/gcc_all
2 sudo mkdir -p /opt/cross-pi-gcc
3 sudo chown $USER /opt/cross-pi-gcc
4 export PATH=/opt/cross-pi-gcc/bin:$PATH

复制里面文件夹中的内核头文件,有关内核的更多信息请参阅Raspbian文档:

1 cd ~/gcc_all
2 cd linux
3 KERNEL=kernel7
4 make ARCH=arm INSTALL_HDR_PATH=/opt/cross-pi-gcc/arm-linux-gnueabihf headers_install

继续,让我们构建 Binutils:

交叉编译gcc源码-将 GCC 构建为 Raspberry-Pi 的交叉编译器

1 cd ~/gcc_all
2 mkdir build-binutils && cd build-binutils
3 ../binutils-2.31/configure --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib
4 make -j 8
5 make install

GCC 和 Glibc 是相互依赖的交叉编译gcc源码,你不能完全构建一个而没有另一个,所以我们将部分构建 GCC,部分构建 Glibc,最后构建 GCC 和 Glibc。 您可以在 Preshing 的文章中了解更多信息。

1 cd ~/gcc_all
2 mkdir build-gcc && cd build-gcc
3 ../gcc-8.3.0/configure --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib
4 make -j8 all-gcc
5 make install-gcc

现在,让我们部分构建 Glibc:

1 cd ~/gcc_all
2 mkdir build-glibc && cd build-glibc
3 ../glibc-2.28/configure --prefix=/opt/cross-pi-gcc/arm-linux-gnueabihf --build=$MACHTYPE --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf --with-arch=armv6 --with-fpu=vfp --with-float=hard --with-headers=/opt/cross-pi-gcc/arm-linux-gnueabihf/include --disable-multilib libc_cv_forced_unwind=yes
4 make install-bootstrap-headers=yes install-headers
5 make -j8 csu/subdir_lib
6 install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib
7 arm-linux-gnueabihf-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /opt/cross-pi-gcc/arm-linux-gnueabihf/lib/libc.so
8 touch /opt/cross-pi-gcc/arm-linux-gnueabihf/include/gnu/stubs.h

回到海湾合作委员会:

1 cd ..
2 cd build-gcc
3 make -j8 all-target-libgcc
4 make install-target-libgcc

完整的 Glibc:

1 cd ..
2 cd build-glibc
3 make -j8
4 make install

完成GCC8.3.0的建立:

1 cd ..
2 cd build-gcc
3 make -j8
4 make install
5 cd ..

或者,编写一个小的 C 或 C++ 测试程序,您可以重构代码:

1 arm-linux-gnueabihf-g++ test.cpp -o test

里面的可执行测试是用我们的第一个交叉编译器构建的,将在您的 Pi 上运行。 可以使用file命令来检测:

1 $ file test
2 test: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, not stripped

更好的测试是将之前创建的 2 的补码文件传输到 RPi,然后就可以运行它了。

现在,您已经在 GCC8.3.0 中拥有了完整的交叉编译器工具链。 在继续下一步之前,请先进行备份,以防出现问题:

1 sudo cp -r /opt/cross-pi-gcc /opt/cross-pi-gcc-8.3.0
1 cd ~/gcc_all

编辑 gcc-10.1.0/libsanitizer/asan/asan_linux.cpp。 如果 PATH_MAX 未定义,则需要定义它。 在第 66 行之后添加下一段代码:

1 #ifndef PATH_MAX
2 #define PATH_MAX 4096
3 #endif

保存并关闭文件。

接下来,我们将使用之前构建的 Glibc 来构建一个更现代的交叉编译器,该编译器将覆盖 GCC8.3:

1 cd ~/gcc_all
2 mkdir build-gcc10 && cd build-gcc10
3 ../gcc-10.1.0/configure --prefix=/opt/cross-pi-gcc --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib
4 make -j8
5 make install

现在,您可以使用 GCC 10.1 为 RaspberryPi 交叉编译任何 C、C++ 或 Fortran 代码。 您可以使用前缀调用任何交叉编译器:

1 arm-linux-gnueabihf-
examples: arm-linux-gnueabihf-gcc, arm-linux-gnueabihf-g++, arm-linux-gnueabihf-gfortran.

为了对交叉编译器进行压力测试,我们用它来对 Pi 进行交叉编译:

1 sudo mkdir -p /opt/gcc-10.1.0
2 sudo chown $USER /opt/gcc-10.1.0
3 
4 cd ~/gcc_all
5 mkdir build-native-gcc10 && cd build-native-gcc10
6 ../gcc-10.1.0/configure --prefix=/opt/gcc-10.1.0 --build=$MACHTYPE --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib --program-suffix=-10.1
7 make -j 8
8 make install-strip

您应该在 /opt/gcc-10.1.0 文件夹中获得本机 ARMGCC。

顺便说一句,在 Debian10x86-64 机器上,使用之前的交叉编译器构建 GCC10.1 大约需要 30 分钟。 与我过去花费 5 个小时直接在 Pi3 上构建 GCC8.1 相比,您会发现在主机上拥有交叉编译器的优势。 有人告诉我,在 RaspberryPiZero 上编译 GCC7 需要 5 天!

如果您想将交叉编译器永久添加到您的路径中,可以使用以下命令:

1 echo 'export PATH=/opt/cross-pi-gcc/bin:$PATH' >> ~/.bashrc
2 source ~/.bashrc

现在您可以选择安全删除构建文件夹。 假设您遵循了我的建议,请在您的主文件夹中使用下一个命令:

1 cd ~
2 rm -rf gcc_all

让我们归档本机 GCCARM 编译器并将其保存到我们的主文件夹中:

1 cd /opt
2 tar -cjvf ~/gcc-10.1.0-armhf-raspbian.tar.bz2 gcc-10.1.0
3 cd ~

将 gcc-10.1.0-armhf-raspbian.tar.bz2 复制到您的 RPi。 在本文的其余部分中,我假设您使用的是 RPi,且存档位于您的主文件夹中:

1 cd ~
2 tar xvf gcc-10.1.0-armhf-raspbian.tar.bz2
3 rm gcc-10.1.0-armhf-raspbian.tar.bz2
4 sudo mv gcc-10.1.0 /opt

接下来,我们将新编译器添加到路径并创建一些符号链接:

 1 echo 'export PATH=/opt/gcc-10.1.0/bin:$PATH' >> ~/.bashrc
 2 echo 'export LD_LIBRARY_PATH=/opt/gcc-10.1.0/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
 3 source ~/.bashrc
 4 sudo ln -s /usr/include/arm-linux-gnueabihf/sys /usr/include/sys
 5 sudo ln -s /usr/include/arm-linux-gnueabihf/bits /usr/include/bits
 6 sudo ln -s /usr/include/arm-linux-gnueabihf/gnu /usr/include/gnu
 7 sudo ln -s /usr/include/arm-linux-gnueabihf/asm /usr/include/asm
 8 sudo ln -s /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/crti.o
 9 sudo ln -s /usr/lib/arm-linux-gnueabihf/crt1.o /usr/lib/crt1.o
10 sudo ln -s /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/crtn.o

此时,您应该能够使用 gcc-10.1、g+±10.1 或 gfortran-10.1 调用编译器。

让我们尝试编译并运行一个使用带有 init 语句的 if 块的 c++17 代码(这个示例有点愚蠢,但它将向您展示如何编译 c++17 程序):

 1 #include 
 2 
 3 int main() {
 4     // if block with init-statement:
 5     if(int a = 5; a < 8) {
 6         std::cout << "Local variable a is < 8n";
 7     } else {
 8         std::cout << "Local variable a is >= 8n";
 9     }
10     return 0;
11 }

将上述代码保存在名为 if_test.cpp 的文件中,并使用以下命令进行编译

1 g++-10.1 -std=c++17 -Wall -pedantic if_test.cpp -o if_test

这是我在 RPi 上看到的内容:

1 pi@raspberrypi:~ $ g++-10.1 -std=c++17 -Wall -pedantic if_test.cpp -o if_test
2 pi@raspberrypi:~ $ ./if_test
3 Local variable a is < 8
4 pi@raspberrypi:~ $

让我们尝试使用 c++17 文件系统:

1 #include 
2 #include 
3 
4 int main() {
5     for(auto &file : std::filesystem::recursive_directory_iterator("./")) {
6         std::cout << file.path() << 'n';
7     }
8 }

将上述代码保存在名为 fs_test.cpp 的文件中,并使用以下命令进行编译:

1 g++-10.1 -std=c++17 -Wall -pedantic fs_test.cpp -o fs_test

这是我在RPi上看到的(如果你有很多文件,请不要在主文件夹中运行接下来的代码,因为它会递归复制所有文件,例如,你可以将其连接到文件较少的文件夹中):

 1 pi@raspberrypi:~ $ g++-10.1 -std=c++17 -Wall -pedantic fs_test.cpp -o fs_test
 2 pi@raspberrypi:~ $ ./fs_test
 3 "./.nano"
 4 "./.profile"
 5 "./.bash_logout"
 6 "./fs_test.cpp"
 7 "./.bashrc"
 8 "./if_test.cpp"
 9 "./if_test"
10 "./fs_test"
11 "./.bash_history"
12 pi@raspberrypi:~ $

如果您想了解有关 Kiwi pie 编程的更多信息,一本特别好的书是 Derek Molloy 的《Exploring Kiwi Pie》:

如果你想了解更多关于现代 C++ 的知识,我推荐 Bjarne Stroustroup 的《C++ Journey》:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 交叉编译gcc源码-将 GCC 构建为 Raspberry-Pi 的交叉编译器 https://www.wkzy.net/game/164953.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务