Using Clang to compile for RISC-V
Asked Answered
M

2

5

I am trying to build a hello world program using Clang (version 12.0.1) for RISC-V architecture. I have installed it with LLVM (version 12.0.1) with the following setup:

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

According to here, default LLVM_TARGETS_TO_BUILD is LLVM_ALL_TARGETS, which includes RISC-V.

So I try to compile it with clang --target=riscv64 -march=rv64gc hello_world.c -o hello_world and I am getting the error:

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

At the same time, /opt/risv/, where I have installed the riscv-gnu-toolchain, is in my path, and I can run riscv64-unknown-linux-gnu-gcc hello_world.c -o hello_world without issues.

I am trying on an Ubuntu machine with kernel 5.8.0-63-generic.

Any idea how can I solve this issue and be able to compile RISC-V programs through Clang?

Marrakech answered 29/7, 2021 at 17:23 Comment(0)
A
12

Foreknowledge:

I had same delusion about this: "If llvm is targeting for all backends including riscv, we should be able to compile our codes just giving a clang flag like --target=riscv32, -target riscv64 etc. without doing extra operation" and I had similar question, but it is not like that. Although LLVM supports riscv target, you need to specify sysroot and gcc toolchain for using riscv headers and libraries, in the other words you need cross compilation. (because you are currently operating a system like x86-64 different from riscv and your default libraries are different) That's why you need to link your riscv-gnu-toolchain paths. Here I assume that you built your riscv-gnu-toolchain from github clone.

Note: Some people have problems with first option (1) and please try to use other options (2) (3) (4) firstly. (Look into comments.)

Solution:

1-) You can add these lines as your cmake configuration flags before building your llvm library:

For 32 bit 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}"

For 64 bit 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}"

and then build llvm library again. Probably as you know, in your llvm build directory:

cmake --build .

Here is an example in my case according to your cmake configuration for clearance:

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 .

Also you can set default target triple as riscv with another cmake configuration flag:

For 32 bit riscv:

-DLLVM_DEFAULT_TARGET_TRIPLE="riscv32-unknown-elf"

For 64 bit riscv:

-DLLVM_DEFAULT_TARGET_TRIPLE="riscv64-unknown-elf"

After this you should be able to compile your codes like these examples:

For C:

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

For C++:

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

If you didn't set default target triple with cmake flag, target option should remain:

For C:

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

For C++:

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

2-) You can pass sysroot and gcc toolchain as flags(as in cmake configurations above) while compiling your code without building your library again. However, if you will use this, you need to give these flags in every compilation:

For 32 bit riscv:

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

--gcc-toolchain="{your-riscv-gnu-toolchain-install-or-build-path}"

For 64 bit riscv:

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

--gcc-toolchain="{your-riscv-gnu-toolchain-install-or-build-path}"

Usage of Flags For 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

Usage of Flags For 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-) You can try to pass these flags while compiling (instead of your --target=riscv64 flag) although it is not more healthy than above options. (Attention: difference is only linux keyword, normally it was -target riscv32-unknown-elf):

For 32 bit riscv:

-target riscv32-unknown-linux-elf

For 64 bit riscv:

-target riscv64-unknown-linux-elf

4-) You can use riscv-llvm repo by following given instructions, although it is outdated.

Note: I adapted my file locations to your examples to better understanding.

Further information you can look here: https://github.com/lowRISC/riscv-llvm#how-can-i-build-upstream-llvmclang-and-use-it-to-cross-compile-for-a-riscv32-target

Aleshia answered 29/7, 2021 at 21:44 Comment(12)
Thank you for the detailed reply. I tried (2) first to confirm it and then tried (1). Unfortunately, (1) is still not working: 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)Marrakech
As it seems, it is ignoring the DDEFAULT_SYSROOT and DGCC_INSTALL_PREFIX flags of (1). (2) still works without issues.Marrakech
I tried 2) and I am having trouble with the linker: /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) Seems like clang is trying to use my machine's native linker, which obviously can't handle riscv. I tried the -B flag to specify the riscv linker, no luck. Any ideas?Trematode
@fabian Yes, it is trying to use your native linker. Probably you are using your pre-installed clang on your machine but you cannot use it for riscv. Be sure you cloned llvm library from github and build for riscv or for all targets by adding cmake build option as -DLLVM_TARGETS_TO_BUILD=all or -DLLVM_TARGETS_TO_BUILD="RISCV". Be sure enable clang by adding cmake option as -DLLVM_ENABLE_PROJECTS=clang. And be sure to use clang from your cloned llvm built by giving its location like ~/llvm-project/build/bin/clang.Aleshia
@fabian After this if problem still persists be sure to have riscv32-unknown-elf-ld or riscv64-unknown-elf-ld in your included riscv-gnu-toolchain built like here: ~/riscv-gnu-toolchain/_install/bin/riscv32-unknown-elf-ld and if it is not exist you should cleanly rebuild your riscv-gnu-toolchain.Aleshia
@SpyridonNonServiam sorry for so late answer. No, for (1) it is not ignoring -DDEFAULT_SYSROOT and -DGCC_INSTALL_PREFIX, you can try to compile to assembly or object code, it should work, and if you try clang from any llvm library built without these flags you cannot compile to assembly or object code for riscv. Problem comes after this, the linker gives error.Aleshia
@SpyridonNonServiam You can use gcc linker after compile your code to object code. For example: /home/shc/llvm/llvm-project/build/bin/clang -c --sysroot=/home/shc/riscv/install/riscv64-unknown-elf --gcc-toolchain=/home/shc/riscv/install --target=riscv64 -march=rv64gc -mabi=ilp32 hello.c -o hello.o and after ~/riscv-gnu-toolchain/_install/bin/riscv64-unknown-elf-gcc -march=rv32imac -mabi=ilp32 hello.o -o hello but probably you don't want this way. (Also @fabian you can use seperately gcc linker by this way, too.)Aleshia
@SpyridonNonServiam You can look cross compilation guides for arm and adapt to riscv equivalents: HowToCrossCompileBuiltinsOnArm HowToCrossCompileLLVM Cross-compilationUsingClang. One of the flags might be good to use: -DCMAKE_C_FLAGS="--sysroot={your-riscv-gnu-toolchain-install-or-build-path}/riscv64-unknown-elf" maybe solve your problem.Aleshia
@SpyridonNonServiam Also you already did these but for reminder: be sure enable projects as clang, lld and compiler-rt like using this flag: -DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt", be sure you are building library for riscv target using this flag: -DLLVM_TARGETS_TO_BUILD=all or -DLLVM_TARGETS_TO_BUILD="RISCV"Aleshia
all of this not helps, still unable to find library -lclang_rt.builtins-riscv64Runin
@АлексейХилаев Please try to use other options (2) (3) (4) not (1), they should work. I don't know why you are getting these errors and if you want to use option (1) please post this issue as a seperate question, maybe someone knows or maybe an llvm bug. And also, I will not delete option (1) but edit my answer as 'some people have problems with first option and please try to use other options first'. Sorry but that's all I can do.Aleshia
-DGCC_INSTALL_PREFIX override -DDEFAULT_SYSROOT actually. I tried all of these and many other options, it not help for me. I tried llvm 12-14 versions, and different toolchains. I tried also with ARM and get the same error but builtins_armRunin
R
1

Finally i deal with that! i`m used next keys:

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

and i copied content of esp-toolchain-install/* into llvm-install/*. And clang finally saw all of GCC files:

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
Runin answered 11/11, 2021 at 6:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.