Build LLVM (Cross) Compiler for Risc‐V - soccercheng/pocl-riscv GitHub Wiki
LLVM Directory Structure
#
# Use the following command to organize LLVM directory structure
#
$ export LLVM_VERSION=20.x
$ mkdir llvm; cd llvm
$ mkdir build_${LLVM_VERSION}_cross.riscv_RelWithDebInfo
$ mkdir build_${LLVM_VERSION}_riscv_RelWithDebInfo
$ gitl clone https://github.com/llvm/llvm-project.git
$ cd llvm-project
$ git checkout origin/release/${LLVM_VERSION}
$ export LLVM_SRC=$(realpath -q .)
The directory structure of LLVM looks like the following
./llvm
├── build_20.x_cross.riscv_RelWithDebInfo
├── build_20.x_riscv_RelWithDebInfo
└── llvm-project
Build LLVM Cross Compiler for Risc-V
$ cd build_${LLVM_VERSION}_cross.riscv_RelWithDebInfo
#
# USE_SPLIT_DWARF==True or BUILD_TYPE==Debug might cause
# build fails due to size problem on risc-v platform
#
export LLVM_VERSION=20.x
export USE_SPLIT_DWARF=False
#export BUILD_TYPE=[Release|Debug|RelWithDebInfo|MinSizeRel]
export BUILD_TYPE=RelWithDebInfo
export ENABLE_PROJECTS="clang;lld;clang-tools-extra;polly;mlir"
#export ENABLE_RUNTIMES="libc;libcxxabi;pstl;libcxx"
unset ENABLE_RUNTIMES
export INSTALL_PREFIX=/usr/local/llvm_${LLVM_VERSION}_cross.riscv_${BUILD_TYPE}
$ cmake -S ${LLVM_SRC}/llvm -B . -G "Ninja" \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCLANG_DEFAULT_LINKER=lld \
-DLLVM_ENABLE_PROJECTS=${ENABLE_PROJECTS} \
-DLLVM_ENABLE_RUNTIMES=${ENABLE_RUNTIMES} \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DLLVM_BUILD_LLVM_DYLIB=True \
-DLLVM_USE_SPLIT_DWARF=${USE_SPLIT_DWARF} \
-DLLVM_OPTIMIZED_TABLEGEN=True -DLLVM_CCACHE_BUILD=OFF \
-DLLVM_INSTALL_UTILS=ON -DLLVM_ENABLE_RTTI=TRUE -DLLVM_ENABLE_EH=ON \
-DLLVM_ENABLE_Z3_SOLVER=OFF -DHAVE_POSIX_REGEX=0 \
-DLLVM_ENABLE_BINDINGS=OFF -DLLVM_INCLUDE_TESTS=OFF \
\
-DCMAKE_SYSTEM_NAME=Linux \
-DLLVM_TARGETS_TO_BUILD="RISCV" \
-DLLVM_DEFAULT_TARGET_TRIPLE=riscv64-unknown-linux-gnu \
\
-DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX}
# Build
# For unknown reason, in debug build, USE_SPLIT_DWARF could NOT be turned on
# please use ninja -j <smaller-number> in case RAM/SWAP shortage
# sudo mkdir ${INSTALL_PREFIX}
$ ninja -j $(nproc)
$ ninja install
Build LLVM Native Compiler for Risc-V
$ cd build_${LLVM_VERSION}_riscv_RelWithDebInfo
#
# USE_SPLIT_DWARF==True or BUILD_TYPE==Debug might cause
# build fails due to size problem on risc-v platform
#
export USE_SPLIT_DWARF=False
#export BUILD_TYPE=[Release|Debug|RelWithDebInfo|MinSizeRel]
export BUILD_TYPE=RelWithDebInfo
export ENABLE_PROJECTS="clang;lld;clang-tools-extra;lldb;polly;mlir"
#export ENABLE_RUNTIMES="libc;libcxxabi;pstl;libcxx"
unset ENABLE_RUNTIMES
export INSTALL_PREFIX=/usr/local/llvm_${LLVM_VERSION}_riscv_${BUILD_TYPE}
$ cmake -S ${LLVM_SRC}/llvm -B . -G "Ninja" \
-DCMAKE_TOOLCHAIN_FILE=./riscv64.toolchain.cmake \
\
-DCLANG_DEFAULT_LINKER=lld \
-DLLVM_ENABLE_PROJECTS=${ENABLE_PROJECTS} \
-DLLVM_ENABLE_RUNTIMES=${ENABLE_RUNTIMES} \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DLLVM_BUILD_LLVM_DYLIB=True \
-DLLVM_USE_SPLIT_DWARF=${USE_SPLIT_DWARF} \
-DLLVM_OPTIMIZED_TABLEGEN=True -DLLVM_CCACHE_BUILD=OFF \
-DLLVM_INSTALL_UTILS=ON -DLLVM_ENABLE_RTTI=TRUE -DLLVM_ENABLE_EH=ON \
-DLLVM_ENABLE_Z3_SOLVER=OFF -DHAVE_POSIX_REGEX=0 \
-DLLVM_ENABLE_BINDINGS=OFF -DLLVM_INCLUDE_TESTS=OFF \
\
-DCMAKE_SYSTEM_NAME=Linux \
-DLLVM_TARGETS_TO_BUILD="RISCV" \
-DLLVM_DEFAULT_TARGET_TRIPLE=riscv64-unknown-linux-gnu \
\
-DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX}
# Build
# For unknown reason, in debug build, USE_SPLIT_DWARF could NOT be turned on
# please use ninja -j <smaller-number> in case RAM/SWAP shortage
# sudo mkdir ${INSTALL_PREFIX}
$ ninja -j $(nproc)
$ ninja install
##
# Very Important ........
#
$ sudo mv /usr/local/llvm_${LLVM_VERSION}_riscv_${BUILD_TYPE}/bin/llvm-config \
/usr/local/llvm_${LLVM_VERSION}_riscv_${BUILD_TYPE}/bin/llvm-config.orig
$ sudo cp -a /usr/local/llvm_${LLVM_VERSION}_cross.riscv_${BUILD_TYPE}/bin/llvm-config \
/usr/local/llvm_${LLVM_VERSION}_riscv_${BUILD_TYPE}/bin/llvm-config
riscv64.toolchain.cmake
#include(CMakeForceCompiler)
# usage
# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/rv32imac.cmake ../
# Look for GCC in path
FIND_FILE( RISCV64_GCC_COMPILER "riscv64-linux-gnu-gcc-14" PATHS ENV INCLUDE)
# Select which is found
if (NOT EXISTS ${RISCV64_GCC_COMPILER})
message(FATAL_ERROR "RISCV64 GCC not found. ${RISCV64_GCC_COMPILER}")
endif()
message( "RISCV64 GCC found: ${RISCV64_GCC_COMPILER}")
get_filename_component(RISCV64_TOOLCHAIN_BIN_PATH ${RISCV64_GCC_COMPILER} DIRECTORY)
get_filename_component(RISCV64_TOOLCHAIN_BIN_GCC ${RISCV64_GCC_COMPILER} NAME_WE)
get_filename_component(RISCV64_TOOLCHAIN_BIN_EXT ${RISCV64_GCC_COMPILER} EXT)
message( "RISCV64 GCC Path: ${RISCV64_TOOLCHAIN_BIN_PATH}" )
STRING(REGEX REPLACE "\-gcc-14" "-" CROSS_COMPILE ${RISCV64_TOOLCHAIN_BIN_GCC})
message( "RISCV64 Cross Compile: ${CROSS_COMPILE}" )
# The Generic system name is used for embedded targets (targets without OS) in CMake
#set( CMAKE_SYSTEM_NAME Generic )
set( CMAKE_SYSTEM_NAME Linux )
set( CMAKE_SYSTEM_PROCESSOR riscv64 )
#set( CMAKE_EXECUTABLE_SUFFIX ".elf")
set ( CMAKE_FIND_ROOT_PATH /usr/riscv64-linux-gnu )
set ( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
set ( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
set ( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
# specify the cross compiler. We force the compiler so that CMake doesn't
# attempt to build a simple test program as this will fail without us using
# the -nostartfiles option on the command line
#CMAKE_FORCE_C_COMPILER( "${AARCH64_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}gcc${AARCH64_TOOLCHAIN_BIN_EXT}" GNU )
#CMAKE_FORCE_CXX_COMPILER( "${AARCH64_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}g++${AARCH64_TOOLCHAIN_BIN_EXT}" GNU )
# use gcc
set(CMAKE_ASM_COMPILER ${CROSS_COMPILE}gcc-14)
set(CMAKE_AR ${CROSS_COMPILE}ar)
set(CMAKE_LD ${CROSS_COMPILE}ld)
set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc-14)
set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++-14)
# for h/w float
SET(CMAKE_C_FLAGS "-march=rv64imafdczicsr_zifencei -mabi=lp64d")
SET(CMAKE_CXX_FLAGS "-march=rv64imafdczicsr_zifencei -mabi=lp64d")
# We must set the OBJCOPY setting into cache so that it's available to the
# whole project. Otherwise, this does not get set into the CACHE and therefore
# the build doesn't know what the OBJCOPY filepath is
set( CMAKE_OBJCOPY ${AARCH64_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objcopy
CACHE FILEPATH "The toolchain objcopy command " FORCE )
set( CMAKE_OBJDUMP ${AARCH64_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objdump
CACHE FILEPATH "The toolchain objdump command " FORCE )
# Set the common build flags
# Set the CMAKE C flags (which should also be used by the assembler!
#set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -g3 -mcmodel=medium" )
#set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" )
#set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" )
#set( CMAKE_SHARED_LINKER_FLAGS "-latomic" )