【问题标题】:Using Clang to compile for RISC-V使用 Clang 编译 RISC-V
【发布时间】:2021-10-05 09:00:43
【问题描述】:

我正在尝试使用Clang(版本 12.0.1)为 RISC-V 架构构建一个 hello world 程序。我已经使用LLVM(版本12.0.1)安装了它,设置如下:

cmake -G "Unix Makefiles" \
   -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lldb;compiler-rt;lld;polly;debuginfo-tests" \
   -DCMAKE_BUILD_TYPE=Debug \
   -DLLVM_ENABLE_ASSERTIONS=On \
   ../llvm

根据here,默认LLVM_TARGETS_TO_BUILDLLVM_ALL_TARGETS,其中包括RISC-V。

所以我尝试用clang --target=riscv64 -march=rv64gc hello_world.c -o hello_world 编译它,我得到了错误:

hello_world.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.

同时,我安装了riscv-gnu-toolchain/opt/risv/ 在我的路径中,我可以毫无问题地运行riscv64-unknown-linux-gnu-gcc hello_world.c -o hello_world

我正在使用内核 5.8.0-63-generic 的 Ubuntu 机器上进行尝试。

知道如何解决这个问题并能够通过 Clang 编译 RISC-V 程序吗?

【问题讨论】:

    标签: compilation clang llvm riscv


    【解决方案1】:

    预知:

    我对此有同样的错觉:“如果 llvm 的目标是包括 riscv 在内的所有后端,我们应该能够编译我们的代码,只需给出一个像 --target=riscv32-target riscv64 等的 clang 标志,而不需要做额外的操作”和我有similar question,但不是那样的。虽然 LLVM 支持 riscv 目标,但您需要指定 sysrootgcc toolchain 才能使用 riscv 头文件和库,换句话说,您需要 cross compilation。 (因为您当前运行的系统像 x86-64 与 riscv 不同,并且您的默认库不同)这就是为什么您需要链接您的 riscv-gnu-toolchain 路径。在这里,我假设您从 github 克隆构建了您的 riscv-gnu-toolchain

    注意: 有些人第一个选项(1)有问题,请先尝试使用其他选项(2)(3)(4)。 (查看 cmets。)

    解决方案:

    1-)您可以在构建 llvm 库之前将这些行添加为您的 cmake 配置标志:

    对于 32 位 riscv:

    -DDEFAULT_SYSROOT="{your-riscv-gnu-toolchain-install-or-build-path}/riscv32-unknown-elf"
    
    -DGCC_INSTALL_PREFIX="{your-riscv-gnu-toolchain-install-or-build-path}"
    

    对于 64 位 riscv:

    -DDEFAULT_SYSROOT="{your-riscv-gnu-toolchain-install-or-build-path}/riscv64-unknown-elf"
    
    -DGCC_INSTALL_PREFIX="{your-riscv-gnu-toolchain-install-or-build-path}"
    

    然后再次构建 llvm 库。可能如您所知,在您的 llvm 构建目录中:

    cmake --build .
    

    根据您的 cmake 配置,这是我的示例:

    cmake -G "Unix Makefiles" \
       -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lldb;compiler-rt;lld;polly;debuginfo-tests" \
       -DCMAKE_BUILD_TYPE=Debug \
       -DLLVM_ENABLE_ASSERTIONS=On \
       -DDEFAULT_SYSROOT="/home/shc/riscv/install/riscv64-unknown-elf" \
       -DGCC_INSTALL_PREFIX="/home/shc/riscv/install" \
       ../llvm
    
    cmake --build .
    

    您还可以使用另一个 cmake 配置标志将默认目标三元组设置为 riscv:

    对于 32 位 riscv:

    -DLLVM_DEFAULT_TARGET_TRIPLE="riscv32-unknown-elf"
    

    对于 64 位 riscv:

    -DLLVM_DEFAULT_TARGET_TRIPLE="riscv64-unknown-elf"
    

    在此之后,您应该能够像以下示例一样编译您的代码:

    对于 C:

    /home/shc/llvm/llvm-project/build/bin/clang -march=rv64gc hello_world.c -o hello_world
    

    对于 C++:

    /home/shc/llvm/llvm-project/build/bin/clang++ -march=rv64gc hello_world.cpp -o hello_world
    

    如果您没有使用 cmake 标志设置默认目标三元组,则应保留 target 选项:

    对于 C:

    /home/shc/llvm/llvm-project/build/bin/clang --target=riscv64 -march=rv64gc hello_world.c -o hello_world
    

    对于 C++:

    /home/shc/llvm/llvm-project/build/bin/clang++ --target=riscv64 -march=rv64gc hello_world.cpp -o hello_world
    

    2-) 您可以在编译代码时将sysrootgcc toolchain 作为标志传递(如上面的cmake 配置),而无需再次构建库。但是,如果您要使用它,则需要在每次编译中提供这些标志:

    对于 32 位 riscv:

    --sysroot="{your-riscv-gnu-toolchain-install-or-build-path}/riscv32-unknown-elf"
    
    --gcc-toolchain="{your-riscv-gnu-toolchain-install-or-build-path}"
    

    对于 64 位 riscv:

    --sysroot="{your-riscv-gnu-toolchain-install-or-build-path}/riscv64-unknown-elf"
    
    --gcc-toolchain="{your-riscv-gnu-toolchain-install-or-build-path}"
    

    C 的标志用法:

    /home/shc/llvm/llvm-project/build/bin/clang --sysroot=/home/shc/riscv/install/riscv64-unknown-elf --gcc-toolchain=/home/shc/riscv/install --target=riscv64 -march=rv64gc hello_world.c -o hello_world
    

    C++ 中标志的使用:

    /home/shc/llvm/llvm-project/build/bin/clang++ --sysroot=/home/shc/riscv/install/riscv64-unknown-elf --gcc-toolchain=/home/shc/riscv/install --target=riscv64 -march=rv64gc hello_world.cpp -o hello_world
    

    3-) 您可以尝试在编译时传递这些标志(而不是您的--target=riscv64 标志),尽管它并不比上述选项更健康。 (注意:区别只是linux关键字,一般是-target riscv32-unknown-elf):

    对于 32 位 riscv:

    -target riscv32-unknown-linux-elf
    

    对于 64 位 riscv:

    -target riscv64-unknown-linux-elf
    

    4-)您可以按照给定的说明使用riscv-llvm repo,尽管它已经过时了。

    注意:我根据您的示例调整了我的文件位置,以便更好地理解。

    您可以在这里查看更多信息:https://github.com/lowRISC/riscv-llvm#how-can-i-build-upstream-llvmclang-and-use-it-to-cross-compile-for-a-riscv32-target

    【讨论】:

    • 感谢您的详细回复。我先尝试(2)确认,然后尝试(1)。不幸的是,(1)仍然不起作用:ld.lld: error: unable to find library -lclang_rt.builtins-riscv64 clang-14: error: ld.lld command failed with exit code 1 (use -v to see invocation)
    • 看起来,它忽略了 (1) 的 DDEFAULT_SYSROOT DGCC_INSTALL_PREFIX 标志。 (2) 仍然可以正常工作。
    • 我试过 2) 并且我的链接器有问题:/usr/bin/ld: unrecognised emulation mode: elf32lriscv Supported emulations: elf_x86_64 elf32_x86_64 elf_i386 elf_iamcu i386linux elf_l1om elf_k1om i386pep i386pe clang: error: ld command failed with exit code 1 (use -v to see invocation) 似乎 clang 正在尝试使用我机器的本机链接器,它显然无法处理 riscv。我尝试了 -B 标志来指定 riscv 链接器,但没有运气。有什么想法吗?
    • @fabian 是的,它正在尝试使用您的本机链接器。可能您正在机器上使用预先安装的 clang,但您不能将其用于 riscv。确保您从 github 克隆了 llvm library,并通过将 cmake 构建选项添加为 -DLLVM_TARGETS_TO_BUILD=all-DLLVM_TARGETS_TO_BUILD="RISCV" 为 riscv 或所有目标构建。确保通过将 cmake 选项添加为 -DLLVM_ENABLE_PROJECTS=clang 来启用 clang。并确保使用克隆的 llvm 中的 clang,方法是提供其位置,例如 ~/llvm-project/build/bin/clang
    • @fabian 在此之后如果问题仍然存在,请确保在包含的 riscv-gnu-toolchain 中包含 riscv32-unknown-elf-ldriscv64-unknown-elf-ld,如下所示:~/riscv-gnu-toolchain/_install/bin/riscv32-unknown-elf-ld,如果不存在,您应该干净地重建你的 riscv-gnu-toolchain。
    【解决方案2】:

    我终于解决了!我使用了下一个键:

    cmake -G "Unix Makefiles" \
    -DCMAKE_BUILD_TYPE="Release" \
    -DBUILD_SHARED_LIBS=True \
    -DCMAKE_INSTALL_PREFIX="/home/username/llvm-install" \
    -DLLVM_OPTIMIZED_TABLEGEN=ON -DLLVM_BUILD_TESTS=False \  
    -DDEFAULT_SYSROOT="/home/username/esp-toolchain-install/riscv64-unknown-elf" \
    -DGCC_INSTALL_PREFIX="/home/username/esp-toolchain-install" \
    -DLLVM_ENABLE_PROJECTS="clang;lld" \
    -DLLVM_DEFAULT_TARGET_TRIPLE="riscv64-unknown-elf" \
    -DLLVM_TARGETS_TO_BUILD="RISCV" ../llvm
    

    我将esp-toolchain-install/* 的内容复制到llvm-install/*。而clang终于看到了所有GCC文件:

    clang -v -print-search-dirs 
    clang version 12.0.1 (https://github.com/llvm/llvm-project.git fed41342a82f5a3a9201819a82bf7a48313e296b)
    Target: riscv64-unknown-unknown-elf
    Thread model: posix
    InstalledDir: /home/username/llvm-install/bin
    Found candidate GCC installation: /home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0
    Selected GCC installation: /home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0
    Candidate multilib: rv32i/ilp32;@march=rv32i@mabi=ilp32
    Candidate multilib: rv32im/ilp32;@march=rv32im@mabi=ilp32
    Candidate multilib: rv32iac/ilp32;@march=rv32iac@mabi=ilp32
    Candidate multilib: rv32imac/ilp32;@march=rv32imac@mabi=ilp32
    Candidate multilib: rv32imafc/ilp32f;@march=rv32imafc@mabi=ilp32f
    Candidate multilib: rv64imac/lp64;@march=rv64imac@mabi=lp64
    Candidate multilib: rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d
    Selected multilib: rv64imac/lp64;@march=rv64imac@mabi=lp64
    programs: =/home/username/llvm-install/bin:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/../../../../bin
    libraries: =/home/username/llvm-install/lib/clang/12.0.1:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/rv64imac/lp64:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/lib/rv64imac/lp64:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0:/home/username/esp-toolchain-install/riscv64-unknown-elf/lib
    

    【讨论】:

      猜你喜欢
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      • 2022-11-08
      • 2021-08-05
      • 1970-01-01
      • 1970-01-01
      • 2022-12-17
      • 2017-01-18
      相关资源
      最近更新 更多