交叉编译之为RISC v平台编译x86的gcc

读者应该比较了解交叉编译的概念,一般都是在x86平台下使用gcc编译出其它平台的代码,这里我尝试在RISC v平台下编译出可以在x86平台使用的代码。

环境

  1. 在 x86_64 平台上编译 riscv64-unknown-linux-gnu-gcc 编译器,网上教程很多不再赘述
  2. 在 x86_64 平台上使用 riscv64-unknown-linux-gnu-gcc 编译出能够在RISC v平台上使用的 x86_64 gcc

请在命令行中输入以下命令测试riscv编译器是否能够正常工作:

riscv64-unknown-linux-gnu-gcc -v

下载源码

根据 https://gcc.gnu.org/install/prerequisites.html 中的说明下载对应版本的MPFR\MPC\ISL\GMP源码和gcc的源码。

wget http://ftpmirror.gnu.org/binutils/binutils-2.38.tar.gz
wget http://ftpmirror.gnu.org/gcc/gcc-11.1.0/gcc-11.1.0.tar.gz
wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.10.5.tar.xz
wget http://ftpmirror.gnu.org/glibc/glibc-2.33.tar.xz
wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz

解压缩

for f in *.tar*; do tar xf $f; done

设置变量

下面的变量的设置一定不要使用export,这里只是设置的变量,而非环境变量。如果使用环境变量,可能会出错!!!

# ROOT 是 源码文件的跟路径
ROOT=/root/x86-gcc
GCCSRC=$ROOT/gcc-11.1.0
BINUTILS=$ROOT/binutils-2.38
LINUX=$ROOT/linux-5.10.5
GLIBC=$ROOT/glibc-2.33

BUILD=x86_64-linux-gnu
HOST=riscv64-unknown-linux-gnu
TARGET=x86_64-linux-gnu
TARGET_ARCH=x86_64

# PREFIX 是把交叉编译器安装到哪里
PREFIX=/opt/$TARGET
SYSROOT=$PREFIX/sysroot

创建文件夹

rm -rf $PREFIX
mkdir -p $SYSROOT

编译binutils

rm -rf $BINUTILS/build-${TARGET}
mkdir $BINUTILS/build-${TARGET}
cd $BINUTILS/build-${TARGET}
../configure --host=$HOST --target=${TARGET} \
    --prefix=${PREFIX} --with-sysroot=$SYSROOT \
    --disable-multilib --disable-werror
make -j32
make install

安装Linux头文件

cd $LINUX
make mrproper
make ARCH=${TARGET_ARCH} INSTALL_HDR_PATH=$SYSROOT/usr headers_install

编译 gcc

准备文件

下载gmp、mpfr、mpc和isl:

cd $GCCSRC
./contrib/download_prerequisites

如果下载成功将会看到如下输出:

gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.18.tar.bz2: OK
All prerequisites downloaded successfully.

将cloog链接到GCC目录:

cd $GCCSRC
ln -s $ROOT/cloog-0.18.1 cloog
file cloog # 确认一下软链接是否成功

编译

这里会出现 fenv.h:58:11: error: ‘::fenv_t’ has not been declared,解决方法见链接的 comment13。这里直接给出解决方案:
修改$GCCSRC/configure,找到RAW_CXX_FOR_TARGET="$CXX_FOR_TARGET",将其修改为RAW_CXX_FOR_TARGET="$CXX_FOR_TARGET -nostdinc++";修改$GCCSRC/configure.ac,找到RAW_CXX_FOR_TARGET="$CXX_FOR_TARGET",将其修改为RAW_CXX_FOR_TARGET="$CXX_FOR_TARGET -nostdinc++"

rm -rf $GCCSRC/build-${TARGET}
mkdir $GCCSRC/build-${TARGET}
cd $GCCSRC/build-${TARGET}
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80196
# 这里会出现 fenv.h:58:11: error: ‘::fenv_t’ has not been declared
# 解决方法见链接的 comment13
../configure --host=$HOST   --target=${TARGET} \
    --prefix=${PREFIX} --with-sysroot=$SYSROOT \
    --enable-languages=c,c++ \
    --enable-threads=posix \
    --disable-multilib --disable-werror --without-selinux --disable-libstdcxx-pch \
    --disable-libmudflap --disable-libssp --disable-libquadmath \
    --disable-libsanitizer --disable-nls
make -j32 
make install

编译glibc

rm -rf $GLIBC/build-${TARGET}
mkdir $GLIBC/build-${TARGET}
cd $GLIBC/build-${TARGET}
../configure --build=$BUILD --host=$TARGET --target=${TARGET} \
    --prefix=$SYSROOT/usr \
    --with-headers=$SYSROOT/usr/include \
    --enable-threads=posix \
    --without-selinux \
    --disable-multilib libc_cv_forced_unwind=yes --disable-libstdcxx-pch \
    --disable-libmudflap --disable-libssp --disable-libquadmath \
    --disable-libsanitizer --disable-nls
make -j64

make install_root=$SYSROOT install

测试

测试文件

main.c

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("Hello, world!\n");
    return 0;
}

hello.cpp

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

int main(int argc, char const *argv[])
{
    std::cout << "Hello, world!" << std::endl;
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::for_each(v.begin(), v.end(), [](int i) { std::cout << i << std::endl; });
    
    return 0;
}

测试

export LD_LIBRARY_PATH=/opt/riscv-gnu-toolchain/sysroot/lib64/lp64d
cd $ROOT/test
$PREFIX/bin/x86_64-linux-gnu-gcc -o main main.c 
$PREFIX/bin/x86_64-linux-gnu-g++ -o hello hello.cpp

参考文献

Ubuntu构建ARM交叉编译器
insall gcc
编译工具链

posted @ 2023-06-13 20:47  LightningStar  阅读(643)  评论(0编辑  收藏  举报