I am trying to build LLVM project for x86 (host), Sparc and RISCV. I have, apparently done that successfully with: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/home/march/opt/llvm -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;openmp" -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" -DLLVM_TARGETS_TO_BUILD="X86;Sparc;RISCV" -DLLVM_INSTALL_UTILS=ON ../llvm
I say apparently because after building I can successfully use clang hello.c, but when I try to do the same for a different target i.e. clang hello.c --target=riscv32 I encounter two errors:
stdio.h file not found: I can solve this by running clang hello.c --target=riscv32 -I/home/march/opt/gcc-riscv-gaisler/riscv-gaisler-elf/include
ld.lld command failed: This can be solved by doing the compilation manually for each step, and then perform the linking using /home/march/opt/gcc-riscv-gaisler/bin/riscv-gaisler-elf-gcc
In both cases I depend on a GCC implementation, which, although allows me to generate code is not a permanent solution.
What do I need to do in order for my LLVM installation to be not dependent on a GCC implementation for each architecture?
The short answer is build a sysroot using your bare-metal libc of choice (newlib is a common one) and point Clang at it with --sysroot. For your stdio.h workaround you’re not using GCC for anything other than the sysroot it provides, and for the ld.lld workaround, which is presumably because you have no standard library (and CRT) files to link against, you’re using GCC both to invoke BFD (which should not be necessary) and to get the files you need. I imagine clang --sysroot=/home/march/opt/gcc-riscv-gaisler/riscv-gaisler-elf would resolve both your issues and demonstrate that it’s just a sysroot you need (and if you do have errors with that, please post them here so we can actually help without guessing; “ld.lld command failed” is not very helpful).
I also tested for Sparc and in this case not even the stdio.h error was solved.
Here I see that is searching in /home/march/opt/gcc-sparc-gaisler/sparc-gaisler-elf/usr/include so I guess this can be easily solved.
SPARC and RISC-V likely have different defaults here. LLD doesn’t even support pre-v9 SPARC so it’s always going to have to use GNU tools for that. For RISC-V you’re getting a Clang that wants to use compiler-rt by default; either build a compiler-rt for it or use --rtlib=libgcc (I think that’s the option). For SPARC some of the behaviour comes from the fact that bare-metal toolchains aren’t really supported - BareMetal::handlesTarget only accepts Arm (32-bit and 64-bit) and RISC-V - so it’s falling back on generic ELF which behaves a bit differently and is more of a “generic but unknown ELF-using OS” driver, I believe.
What’s the intended target? Baremetal, Linux, or some other OS? And which libc would you like to use? This is important to give a useful answer.
If Linux, you can build your own sysroot using compiler-rt and musl to build static executables (this is slightly involved but possible). For baremetal there are other libc variants, my preferred one is picolibc. If you target a particular Linux distribution you could also obtain a sysroot by downloading a rootfs (via LXC, Docker, or some other way) and using it in --sysroot.
In any case, you probably need to use -fuse-ld=lld to avoid linking with GNU ld.
The important thing to know is that the libc (and therefore stdio.h) is not part of the LLVM build. You have to supply one yourself if you’re cross compiling.
I have been able to link using lld for RISC-V. Regarding linking with the appropriate libraries I see there is no current way to do that with just LLVM.
I have found this video on how to use llvm libc, although the support is not completed it may be of help for someone. However there is no support for RISC-V (link)