#! /bin/bash # Toolchain builder for the Serene programming language # # Copyright (c) 2019-2023 Sameer Rahmani # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ----------------------------------------------------------------------------- # Commentary # ----------------------------------------------------------------------------- # This is the builder script for the Serene project. It makes it easier to # interact with the CMake build scripts. # # In order to define a subcommand all you need to do is to define a function # with the following syntax: # # function subcommand-name() { ## DESCRIPTION # .. subcommand body .. # } # # Make sure to provid one line of DESCRIPTION for the subcommand and use two "#" # characters to start the description following by a space. Otherwise, your # subcommand won't be registered # set -e command=$1 VERSION="0.9.0" LLVM_VERSION="da3cd333bea572fb10470f610a27f22bcb84b08c" LLVM_MAJOR_VERSION="16" CMAKE_VERSION="3.26.0" NINJA_VERSION="1.11.1" ZLIB_VERSION="1.2.13" ZSTD_VERSION="1.5.4" KERNEL_VERSION="6.0" MUSL_VERSION="1.2.3" IWYU_VERSION="35fed15e53d92c8c540f0c00ac10077043126c4d" BOEHMGC_VERSION="8.2.2" DEV_HEROES="https://devheroes.codes" TARGET=x86_64-pc-linux-musl export LLVM_VERSION \ CMAKE_VERSION \ NINJA_VERSION \ ZLIB_VERSION \ ZSTD_VERSION \ KERNEL_VERSION \ LLVM_MAJOR_VERSION \ MUSL_VERSION \ TARGET \ IWYU_VERSION \ BOEHMGC_VERSION \ DEV_HEROES ME=$(cd "$(dirname "$0")/." >/dev/null 2>&1 ; pwd -P) # shellcheck source=./scripts/utils.sh source "$ME/scripts/utils.sh" user="serene" channel="stable" function _conan() { ## A conan wrapper PYTHONPATH="$ME:$PYTHONPATH" conan "$@" } function _create() { _conan create --user "$user" --channel "$channel" \ --profile:host="$ME/profiles/stage$1" \ --profile:build="$ME/profiles/stage$1" \ "${@:2}" . } function _build() { _push "packages/$1/" _create "${@:2}" _pop } function _deploy() { mkdir -p "$ME/.tmp/$2/" _conan install --deploy "$ME/conf/${4:-tarball_deployer.py}" \ --requires "$1/$2@$user/$channel" \ --profile:host="$ME/profiles/stage$3" \ --profile:build="$ME/profiles/stage$3" \ -of "$ME/.tmp/$3/" \ } function graph() { ## Generate the dependency graph _push "packages/$1/" _conan graph info \ --user "$user" --channel "$channel" -v \ --profile:host="../../profiles/stage$2" \ --profile:build="../../profiles/stage$2" \ conanfile.py \ "${@:3}" _pop } function llvm-source() { ## Build the llvm source pkg _push "packages/sources/llvm/" _conan create --user "$user" --channel "$channel" \ --profile:host="../../../profiles/stage$1" \ --profile:build="../../../profiles/stage$1" \ . "${@:2}" _pop } # A glibc clang with a sysroot containing musl, libc++ function build-stage1() { ## Build the stage1 compiler and sysroot llvm-source 0 _build cmake 0 _build ninja 0 _build zlib-bootstrap 0 _build zstd-bootstrap 0 _build clang-bootstrap 0 _build kernel-headers 1 _build musl 1 _build zlib 1 _build zstd 1 _build libcxx 1 _build stage1-bundle 1 # All this is because conan does not support removing dependencies yet # So we ended up hacking our way through to create some # packages that do now have any dependency rm -rf "$ME/.tmp" rm -rf "$ME/packages/stage1-sysroot/sysroot/" _deploy "stage1-bundle" "$LLVM_VERSION" 1 mkdir -p "$ME/packages/stage1-sysroot/sysroot/" cp -rv "$ME/.tmp/1/stage1-bundle/$LLVM_VERSION/" "$ME/packages/stage1-sysroot/sysroot/" _build stage1-sysroot 1 rm -rf "$ME/packages/stage1-sysroot/sysroot/" "$ME/.tmp" } # A musl clang with the sysroot function build-stage2() { ## Build the stage2 compiler and sysroot #llvm-source 1 _build cmake 1 _build ninja 1 _build clang 1 _build musl 2 _build zlib 2 _build zstd 2 _build stage2-bundle 2 # All this is because conan does not support removing dependencies yet # So we ended up hacking our way through to create some # packages that do now have any dependency rm -rf "$ME/.tmp" rm -rf "$ME/packages/stage2-sysroot/sysroot/" _deploy "stage2-bundle" "$LLVM_VERSION" 2 mkdir -p "$ME/packages/stage2-sysroot/sysroot/" cp -rv "$ME/.tmp/2/stage2-bundle/$LLVM_VERSION/" "$ME/packages/stage2-sysroot/sysroot/" _build stage2-sysroot 2 rm -rf "$ME/packages/stage2-sysroot/sysroot/" "$ME/.tmp" } # final toolchain function build-stage3() { ## Build the stage3 compiler and sysroot _build iwyu 2 _build toolchain 2 _build boehmgc 2 _build stage3-bundle 2 # All this is because conan does not support removing dependencies yet # So we ended up hacking our way through to create some # packages that do now have any dependency rm -rf "$ME/.tmp" rm -rf "$ME/packages/stage3-sysroot/sysroot/" _deploy "stage3-bundle" "$LLVM_VERSION" 2 mkdir -p "$ME/packages/stage3-sysroot/sysroot/" cp -rv "$ME/.tmp/2/stage3-bundle/$LLVM_VERSION/" "$ME/packages/stage3-sysroot/sysroot/" _build stage3-sysroot 2 rm -rf "$ME/packages/stage3-sysroot/sysroot/" "$ME/.tmp" } function compress_tarball() { local ZSTD_CLI ZSTD_CLI="zstd --ultra -22 -T$(nproc)" tar -I "$ZSTD_CLI" -cf "serene_toolchain.$LLVM_MAJOR_VERSION.$LLVM_VERSION.tar.zstd" \ -C "$ME/.tmp/2/stage3-sysroot/" . } function build-tarball() { ## Create the toolchain tarball _deploy "stage3-sysroot" "$LLVM_VERSION" 2 "toolchain_deployer.py" echo "Creating the tarball..." compress_tarball } function build-toolchain() { ## Build the entire thing build-stage1 build-stage2 build-stage3 build-tarball } function test-container() { ## Run an alpine container to test the toolchain in the .tmp dir # Make sure to run the build-stage3 first so the .tmp/2/stage3-sysroot/ exist docker run --rm -it -v "$ME/.tmp/2/stage3-sysroot/":/sysroot \ -v "$ME/tests/":/tests \ alpine:latest /bin/sh } function http_push() { if [[ -z "$DEV_HEROES_TOKEN" ]]; then error "\$DEV_HEROES_TOKEN is not set." exit 1 fi local pkg_name local version pkg_name="$1" version="$2" echo "Uploading '$pkg_name.$version.tar.zstd' to '$DEV_HEROES/api/packages/serene/generic/$pkg_name/$version/$pkg_name.$version.tar.zstd'" curl "$DEV_HEROES/api/packages/serene/generic/$pkg_name/$version/$pkg_name.$version.tar.zstd" \ --upload-file "$pkg_name.$version.tar.zstd" \ --progress-bar \ -H "accept: application/json" \ -H "Authorization: token $DEV_HEROES_TOKEN" \ -H "Content-Type: application/json" } function push() { ## Push the final tarball to the repository # NOTE: You need to provide $DEV_HEROES_TOKEN while calling the push # subcommand http_push "serene_toolchain" "$LLVM_MAJOR_VERSION.$LLVM_VERSION" } function help() { ## Print out this help message echo "Commands:" grep -E '^function [a-zA-Z0-9_-]+\(\) \{ ## .*$$' "$0" | \ sort | \ sed 's/^function \([a-zA-Z0-9_-]*\)() { ## \(.*\)/\1:\2/' | \ awk 'BEGIN {FS=":"}; {printf "\033[36m%-30s\033[0m %s\n", $1, $2}' } # ----------------------------------------------------------------------------- # Main logic # ----------------------------------------------------------------------------- echo -e "\nSerene Builder Version $VERSION" echo -e "\nCopyright (C) 2019-2023" echo -e "Sameer Rahmani " echo -e "Serene comes with ABSOLUTELY NO WARRANTY;" echo -e "This is free software, and you are welcome" echo -e "to redistribute it under certain conditions;" echo -e "for details take a look at the LICENSE file.\n" if [[ -d "$ME/packages/$command" ]]; then _build "$command" "${@:2}" exit $? fi # Find the subcommand in the functions and run we find it. for fn in $(fn-names); do if [[ $fn == "$command" ]]; then eval "$fn ${*:2}" exit $? fi done # If we couldn't find the command print out the help message help