diff --git a/tools/setup-toolchain b/tools/setup-toolchain new file mode 100755 index 0000000..3827d71 --- /dev/null +++ b/tools/setup-toolchain @@ -0,0 +1,264 @@ +#!/bin/bash +# Copyright © 2023, d0p1 +# +# This file is part of Fukurō. +# +# This software is governed by the CeCILL license under French law and +# abiding by the rules of distribution of free software. You can use, +# modify and/ or redistribute the software under the terms of the CeCILL +# license as circulated by CEA, CNRS and INRIA at the following URL +# "http://cecill.info". +# +# As a counterpart to the access to the source code and rights to copy, +# modify and redistribute granted by the license, users are provided only +# with a limited warranty and the software's author, the holder of the +# economic rights, and the successive licensors have only limited +# liability. +# +# In this respect, the user's attention is drawn to the risks associated +# with loading, using, modifying and/or developing or reproducing the +# software by the user in light of its specific status of free software, +# that may mean that it is complicated to manipulate, and that also +# therefore means that it is reserved for developers and experienced +# professionals having in-depth computer knowledge. Users are therefore +# encouraged to load and test the software's suitability as regards their +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the +# same conditions as regards security. +# +# The fact that you are presently reading this means that you have had +# knowledge of the CeCILL license and that you accept its terms. + +set -o errexit +set -o nounset +set -o pipefail + +BINUTILS_VERSION=2.41 +BINUTILS_ARCHIVE="binutils-${BINUTILS_VERSION}.tar.gz" +BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/${BINUTILS_ARCHIVE}" +BINUTILS_SHA256="48d00a8dc73aa7d2394a7dc069b96191d95e8de8f0da6dc91da5cce655c20e45" + +GCC_VERSION=13.2.0 +GCC_ARCHIVE="gcc-${GCC_VERSION}.tar.gz" +GCC_URL="https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/${GCC_ARCHIVE}" +GCC_SHA256="8cb4be3796651976f94b9356fa08d833524f62420d6292c5033a9a26af315078" + +cerror="\033[31m" +cwarn="\033[33m" +cok="\033[32m" +creset="\033[0m" + +target_triple=riscv-elf +install_prefix="${HOME}/.toolchain" +do_sha256_check=yes +do_force=no +do_update=no +do_build_binutils=no +do_build_gcc=no + +warn() { + printf "[${cwarn}WARN${creset}] %s\n" "$1" +} + +fatal() { + printf "[${cerror}FATAL${creset}] %s\n" "$1" + exit 255 +} + +finish() { + if [ -d "${install_prefix}/build" ]; then + ( + cd "${install_prefix}/build" + rm -rf "binutils-${BINUTILS_VERSION}" + rm -rf "gcc-${GCC_VERSION}" + ) + fi +} +trap finish EXIT ERR + +setup() { + wget_exe=`which wget` + curl_exe=`which curl` + sha256sum_exe=`which sha256sum` + + if [ x"$sha256sum_exe" = "x" ]; then + warn "sha256sum not found; sha256 check will be skipped" + do_sha256_check=no + fi +} + +verify() { + printf "checking %s sha256 hash... " "$1" + if [ x"$do_sha256_check" = "xyes" ]; then + sha256sum -c <(printf "%s %s\n" "$2" "$1") > /dev/null && printf "${cok}OK${creset}\n" || (printf "${cerror}FAILED${creset}\n" && false) + else + printf "${cwarn}SKIP${creset}\n" + fi +} + +check_current_binutils_version() { + printf "checking binutils version... " + if "${target_triple}-ld" --version | grep "${BINUTILS_VERSION}" >/dev/null; then + printf "${cok}OK${creset}\n" + else + printf "${cwarn}MISSMATCH${creset}\n" + if [ x"$do_update" = "xyes" ]; then + do_build_binutils=yes + fi + fi +} + +check_current_binutils() { + printf "checking for %s-ld... " "${target_triple}" + if command -v "${target_triple}-ld" > /dev/null; then + printf "${cok}FOUND${creset}\n" + + check_current_binutils_version + else + printf "${cerror}NO${creset}\n" + do_build_binutils=yes + fi +} + +check_current_gcc_version() { + printf "checking gcc version... " + if "${target_triple}-gcc" --version | grep "${GCC_VERSION}" >/dev/null; then + printf "${cok}OK${creset}\n" + else + printf "${cwarn}MISSMATCH${creset}\n" + if [ x"$do_update" = "xyes" ]; then + do_build_gcc=yes + fi + fi +} + +check_current_gcc() { + printf "checking for %s-gcc... " "${target_triple}" + if command -v "${target_triple}-gcc" > /dev/null; then + printf "${cok}FOUND${creset}\n" + + check_current_gcc_version + else + printf "${cerror}NO${creset}\n" + do_build_gcc=yes + fi +} + +download() { + for i in 1 2 3; do + if [ ! -f "$1" ]; then + $wget_exe -O "$1" "$2" + fi + + if verify "$1" "$3"; then + break + else + rm "$1" + fi + done + + test -f "$1" +} + +build_binutils() { + ( + cd "${install_prefix}/build" + download "${BINUTILS_ARCHIVE}" "${BINUTILS_URL}" "${BINUTILS_SHA256}" + + printf "extract %s\n" "${BINUTILS_ARCHIVE}" + tar -xf "${BINUTILS_ARCHIVE}" + ( + cd "binutils-${BINUTILS_VERSION}" + mkdir -p build + ( + cd build + ../configure --target="${target_triple}" --prefix="${install_prefix}" --with-sysroot --disable-nls --disable-werror + make -j $(nproc) + make install + ) + ) + ) +} + +build_gcc() { + ( + cd "${install_prefix}/build" + download "${GCC_ARCHIVE}" "${GCC_URL}" "${GCC_SHA256}" + + printf "extract %s\n" "${GCC_ARCHIVE}" + tar -xf "${GCC_ARCHIVE}" + ( + cd "gcc-${GCC_VERSION}" + mkdir -p build + ( + cd build + ../configure --target="${target_triple}" --prefix="${install_prefix}" --with-sysroot --disable-nls --enable-languages=c --with-newlib + make -j $(nproc) all-gcc + make -j $(nproc) all-target-libgcc + make -j $(nproc) install-gcc + make -j $(nproc) install-target-libgcc + ) + ) + ) +} + +usage() { + cat <][-p ][-f][-h] + + -t toolchain triple (default: $target_triple) + -p install prefix path (default: $install_prefix) + -f force rebuild (eg: ignore cache when CI build) + -u update if toolchain version missmatch (default: no) + -h display this help and exit + +Report bugs to: +EOF + + exit 0 +} + +main() { + setup + + while getopts 't:p:fh' opt; do + case "$opt" in + t) + target_triple="${OPTARG}" + ;; + p) + install_target="${OPTARG%%/}" + ;; + f) + do_force=yes + ;; + u) + do_update=yes + ;; + ?|h) + usage "${@}" + ;; + esac + done + + PATH="${install_prefix}/bin:${PATH}" + mkdir -p "${install_prefix}/build" + + if [ x"$do_force" = "xyes" ]; then + do_build_binutils=yes + do_build_gcc=yes + else + check_current_binutils + check_current_gcc + fi + + if [ x"$do_build_binutils" = "xyes" ]; then + build_binutils + fi + + if [ x"$do_build_gcc" = "xyes" ]; then + build_gcc + fi +} + +main "${@}"