#!/usr/bin/env bash # # Copyright (C) 2024 Kyle Schwarz , Toni Uhlig # # 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, either version 3 of the License, or # (at your option) any later version. # # 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 . # ROOT_PATH="$HOME/.mingw-w64-build-ng" MINGW_W64_BRANCH="master" BINUTILS_BRANCH="binutils-2_42-branch" GCC_BRANCH="releases/gcc-14" USE_TARBALL_RELEASES=1 MINGW_W64_TARBALL_VERSION="v11.0.0" BINUTILS_TARBALL_VERSION="2.43" GCC_TARBALL_VERSION="14.2.0" MINGW_W64_TARBALL_SHA512="5a0a09a572fcf152ed75c6e7830fd62e6c01decc9cbdba5552d4b9c00eebfa79f98e266ba9e403b184eb5a14bd45b24f5a4c16802a40295464e3323b8f2b11bc" BINUTILS_TARBALL_SHA512="27a19e23b2e8be9994f13687a6e0d6fd6db58f2013d4fd7b1c7f098069fbbee59e6500de4ea16b2218df5f23861f7925472081c3baec7a98533431c2d522c7b1" GCC_TARBALL_SHA512="5d2fdfc296220cc61ea65eaf35d4f880fa557933f3fa3474b5a37008ce186d33a411e4e06a1107d0a55623001708f80b3755618c63ae6d560ec890147371aa69" ENABLE_THREADS="--enable-threads=posix" JOB_COUNT=$(($(getconf _NPROCESSORS_ONLN) + 2)) LINKED_RUNTIME="msvcrt" show_help() { cat <... Archs: i586 Windows 32-bit for old CPUs (Intel Pentium (MMX), AMD K5, K6, K6-2, K6-III) i686 Windows 32-bit (Intel P6 [Pentium Pro], AMD K7 and newer) x86_64 Windows 64-bit Options: -h, --help show help -j , --jobs override make job count (default: $JOB_COUNT) -p , --prefix install location (default: $ROOT_PATH/) -r , --root location for sources, build artifacts and the resulting compiler (default: $ROOT_PATH) --keep-artifacts don't remove source and build files after a successful build --disable-threads disable pthreads and STL --cached-sources use existing sources instead of downloading new ones --binutils-branch NOT RECOMMENDED - set Binutils branch (default: $BINUTILS_BRANCH) --gcc-branch NOT RECOMMENDED - set GCC branch (default: $GCC_BRANCH) --mingw-w64-branch NOT RECOMMENDED - set MinGW-w64 branch (default: $MINGW_W64_BRANCH) --force-git NOT RECOMMENDED - force git clone (default: disabled) --linked-runtime set MinGW Linked Runtime (default: $LINKED_RUNTIME) --tarball generate a toolchain tarball archive (bzip2 compressed) EOF } error_exit() { local error_msg="$1" shift 1 if [ "$error_msg" ]; then printf "%s\n" "$error_msg" >&2 else printf "an error occured\n" >&2 fi exit 1 } arg_error() { local error_msg="$1" shift 1 error_exit "$error_msg, see --help for options" "$error_msg" } execute() { local info_msg="$1" local error_msg="$2" shift 2 if [ ! "$error_msg" ]; then error_msg="error" fi if [ "$info_msg" ]; then printf "(%d/%d): %s\n" "$CURRENT_STEP" "$TOTAL_STEPS" "$info_msg" CURRENT_STEP=$((CURRENT_STEP + 1)) fi "$@" >>"$LOG_FILE" 2>&1 || error_exit "$error_msg, check $LOG_FILE for details" } create_dir() { local path="$1" shift 1 execute "" "unable to create directory '$path'" \ mkdir -p "$path" } remove_path() { local path="$1" shift 1 execute "" "unable to remove path '$path'" \ rm -fr "$path" } change_dir() { local path="$1" shift 1 execute "" "unable to cd to directory '$path'" \ cd "$path" } download_sources() { remove_path "$SRC_PATH" create_dir "$SRC_PATH" change_dir "$SRC_PATH" if [ ${USE_TARBALL_RELEASES} -eq 0 ]; then execute "downloading MinGW-w64 source (GIT+HTTPS)" "" \ git clone --depth 1 -b "$MINGW_W64_BRANCH" \ "https://git.code.sf.net/p/mingw-w64/mingw-w64" mingw-w64 else execute "downloading MinGW-w64 source (TAR+HTTPS)" "" \ curl -o mingw-w64.tar.gz \ "https://codeload.github.com/mirror/mingw-w64/tar.gz/refs/tags/${MINGW_W64_TARBALL_VERSION}" MINGW_W64_sha512sum="$(sha512sum mingw-w64.tar.gz | cut -d ' ' -f 1)" execute "verify MinGW-w64 SHA-512" \ "Hash verification failed; new: ${MINGW_W64_sha512sum}" \ test "${MINGW_W64_sha512sum}" = "${MINGW_W64_TARBALL_SHA512}" execute "extract MinGW-w64 tarball" "" \ tar -xzf mingw-w64.tar.gz --one-top-level=mingw-w64/ --strip-components=1 fi if [ ${USE_TARBALL_RELEASES} -eq 0 ]; then execute "downloading Binutils source (GIT+HTTPS)" "" \ git clone --depth 1 -b "$BINUTILS_BRANCH" \ "https://sourceware.org/git/binutils-gdb.git" binutils else execute "downloading Binutils source (TAR+HTTPS)" "" \ curl -o binutils.tar.gz \ "https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_TARBALL_VERSION}.tar.gz" BINUTILS_sha512sum="$(sha512sum binutils.tar.gz | cut -d ' ' -f 1)" execute "verify Binutils SHA-512" \ "Hash verification failed; new: ${BINUTILS_sha512sum}" \ test "${BINUTILS_sha512sum}" = "${BINUTILS_TARBALL_SHA512}" execute "extract Binutils tarball" "" \ tar -xzf binutils.tar.gz --one-top-level=binutils/ --strip-components=1 fi if [ ${USE_TARBALL_RELEASES} -eq 0 ]; then execute "downloading GCC source (GIT+HTTPS)" "" \ git clone --depth 1 -b "$GCC_BRANCH" \ "https://gcc.gnu.org/git/gcc.git" gcc else execute "downloading GCC source (TAR+HTTPS)" "" \ curl -o gcc.tar.gz \ "https://codeload.github.com/gcc-mirror/gcc/tar.gz/refs/tags/releases/gcc-${GCC_TARBALL_VERSION}" GCC_sha512sum="$(sha512sum gcc.tar.gz | cut -d ' ' -f 1)" execute "verify GCC SHA-512" \ "Hash verification failed; new: ${GCC_sha512sum}" \ test "${GCC_sha512sum}" = "${GCC_TARBALL_SHA512}" execute "extract GCC tarball" "" \ tar -xzf gcc.tar.gz --one-top-level=gcc/ --strip-components=1 fi } build() { local arch="$1" local prefix="$2" shift 2 local bld_path="$BLD_PATH/$arch" local host="$arch-w64-mingw32" export PATH="$prefix/bin:$PATH" remove_path "$bld_path" # don't remove a user defined prefix (could be /usr/local) if [ ! "$PREFIX" ]; then remove_path "$prefix" fi if [ "$arch" = "i586" ] || [ "$arch" = "i686" ]; then local x86_dwarf2="--disable-sjlj-exceptions --with-dwarf2" local crt_lib="--enable-lib32 --disable-lib64" else local x86_dwarf2="" local crt_lib="--enable-lib64 --disable-lib32" fi create_dir "$bld_path/binutils" change_dir "$bld_path/binutils" execute "($arch): configuring Binutils" "" \ "$SRC_PATH/binutils/configure" --prefix="$prefix" --disable-shared \ --enable-static --with-sysroot="$prefix" --target="$host" \ --disable-multilib --disable-nls --enable-lto --disable-gdb execute "($arch): building Binutils" "" \ make -j $JOB_COUNT execute "($arch): installing Binutils" "" \ make install create_dir "$bld_path/mingw-w64-headers" change_dir "$bld_path/mingw-w64-headers" execute "($arch): configuring MinGW-w64 headers" "" \ "$SRC_PATH/mingw-w64/mingw-w64-headers/configure" --build="$BUILD" \ --host="$host" --prefix="$prefix/$host" \ --with-default-msvcrt=$LINKED_RUNTIME execute "($arch): installing MinGW-w64 headers" "" \ make install create_dir "$bld_path/gcc" change_dir "$bld_path/gcc" execute "($arch): configuring GCC" "" \ "$SRC_PATH/gcc/configure" --target="$host" --disable-shared \ --enable-static --disable-multilib --prefix="$prefix" \ --enable-languages=c,c++ --disable-nls $ENABLE_THREADS \ $x86_dwarf2 execute "($arch): building GCC (all-gcc)" "" \ make -j $JOB_COUNT all-gcc execute "($arch): installing GCC (install-gcc)" "" \ make install-gcc create_dir "$bld_path/mingw-w64-crt" change_dir "$bld_path/mingw-w64-crt" execute "($arch): configuring MinGW-w64 CRT" "" \ "$SRC_PATH/mingw-w64/mingw-w64-crt/configure" --build="$BUILD" \ --host="$host" --prefix="$prefix/$host" \ --with-default-msvcrt=$LINKED_RUNTIME \ --with-sysroot="$prefix/$host" $crt_lib execute "($arch): building MinGW-w64 CRT" "" \ make -j $JOB_COUNT execute "($arch): installing MinGW-w64 CRT" "" \ make install if [ "$ENABLE_THREADS" ]; then create_dir "$bld_path/mingw-w64-winpthreads" change_dir "$bld_path/mingw-w64-winpthreads" execute "($arch): configuring winpthreads" "" \ "$SRC_PATH/mingw-w64/mingw-w64-libraries/winpthreads/configure" \ --build="$BUILD" --host="$host" --disable-shared \ --enable-static --prefix="$prefix/$host" execute "($arch): building winpthreads" "" \ make -j $JOB_COUNT execute "($arch): installing winpthreads" "" \ make install fi change_dir "$bld_path/gcc" execute "($arch): building GCC" "" \ make -j $JOB_COUNT execute "($arch): installing GCC" "" \ make install } while :; do case $1 in -h|--help) show_help exit 0 ;; -j|--jobs) if [ "$2" ]; then JOB_COUNT=$2 shift else arg_error "'--jobs' requires a non-empty option argument" fi ;; -p|--prefix) if [ "$2" ]; then PREFIX=$(realpath "$2") shift else arg_error "'--prefix' requires a non-empty option argument" fi ;; --prefix=?*) PREFIX=$(realpath "${1#*=}") ;; --prefix=) arg_error "'--prefix' requires a non-empty option argument" ;; -r|--root) if [ "$2" ]; then ROOT_PATH_ARG="$2" shift else arg_error "'--root' requires a non-empty option argument" fi ;; --root=?*) ROOT_PATH_ARG="${1#*=}" ;; --root=) arg_error "'--root' requires a non-empty option argument" ;; --keep-artifacts) KEEP_ARTIFACTS=1 ;; --disable-threads) ENABLE_THREADS="" ;; --cached-sources) CACHED_SOURCES=1 ;; --binutils-branch) USE_TARBALL_RELEASES=0 if [ "$2" ]; then BINUTILS_BRANCH="$2" shift else arg_error "'--binutils-branch' requires a non-empty option argument" fi ;; --binutils-branch=?*) USE_TARBALL_RELEASES=0 BINUTILS_BRANCH=${1#*=} ;; --binutils-branch=) arg_error "'--binutils-branch' requires a non-empty option argument" ;; --gcc-branch) USE_TARBALL_RELEASES=0 if [ "$2" ]; then GCC_BRANCH="$2" shift else arg_error "'--gcc-branch' requires a non-empty option argument" fi ;; --gcc-branch=?*) USE_TARBALL_RELEASES=0 GCC_BRANCH=${1#*=} ;; --gcc-branch=) arg_error "'--gcc-branch' requires a non-empty option argument" ;; --linked-runtime) if [ "$2" ]; then LINKED_RUNTIME="$2" shift else arg_error "'--linked-runtime' requires a non-empty option argument" fi ;; --linked-runtime=?*) LINKED_RUNTIME=${1#*=} ;; --linked-runtime=) arg_error "'--linked-runtime' requires a non-empty option argument" ;; --mingw-w64-branch) USE_TARBALL_RELEASES=0 if [ "$2" ]; then MINGW_W64_BRANCH="$2" shift else arg_error "'--mingw-w64-branch' requires a non-empty option argument" fi ;; --mingw-w64-branch=?*) USE_TARBALL_RELEASES=0 MINGW_W64_BRANCH=${1#*=} ;; --mingw-w64-branch=) arg_error "'--mingw-w64-branch' requires a non-empty option argument" ;; --force-git) USE_TARBALL_RELEASES=0 ;; --tarball) if [ "$2" ]; then TARBALL=$(realpath "$2") shift else arg_error "'--tarball' requires a non-empty option argument" fi ;; i586) BUILD_I586=1 ;; i686) BUILD_I686=1 ;; x86_64) BUILD_X86_64=1 ;; --) shift break ;; -?*) arg_error "unknown option '$1'" ;; ?*) arg_error "unknown arch '$1'" ;; *) break esac shift done NUM_BUILDS=$((BUILD_I586 + BUILD_I686 + BUILD_X86_64)) if [ "$NUM_BUILDS" -eq 0 ]; then arg_error "no ARCH was specified" fi MISSING_EXECS="" for exec in g++ flex bison git makeinfo m4 bzip2 curl make diff sha512sum cut test; do if ! command -v "$exec" >/dev/null; then MISSING_EXECS="$MISSING_EXECS $exec" fi done if [ "$MISSING_EXECS" ]; then error_exit "missing required executable(s):$MISSING_EXECS" fi TOTAL_STEPS=0 if [ "${USE_TARBALL_RELEASES}" -ne 0 ]; then TOTAL_STEPS=$((TOTAL_STEPS + 6)) fi if [ "$CACHED_SOURCES" ]; then if [ ! -f "$SRC_PATH/mingw-w64.tar.gz" ]; then arg_error "no sources found, run with --keep-artifacts first" fi else TOTAL_STEPS=$((TOTAL_STEPS + 4)) fi if [ "$ENABLE_THREADS" ]; then THREADS_STEPS=3 else THREADS_STEPS=0 fi THREADS_STEPS=$((THREADS_STEPS * NUM_BUILDS)) BUILD_STEPS=$((13 * NUM_BUILDS)) if [ ! -z "${TARBALL}" ]; then TOTAL_STEPS=$((TOTAL_STEPS + 1)) fi TOTAL_STEPS=$((TOTAL_STEPS + THREADS_STEPS + BUILD_STEPS)) if [ "$ROOT_PATH_ARG" ]; then ROOT_PATH=$(mkdir -p "$ROOT_PATH_ARG" && cd "$ROOT_PATH_ARG" && pwd) fi SRC_PATH="$ROOT_PATH/src" BLD_PATH="$ROOT_PATH/bld" LOG_FILE="$ROOT_PATH/build.log" if [ "$PREFIX" ]; then I586_PREFIX="$PREFIX" I686_PREFIX="$PREFIX" X86_64_PREFIX="$PREFIX" else I586_PREFIX="$ROOT_PATH/i586" I686_PREFIX="$ROOT_PATH/i686" X86_64_PREFIX="$ROOT_PATH/x86_64" fi CURRENT_STEP=1 # clean log file for execute() mkdir -p "$ROOT_PATH" rm -f "$LOG_FILE" touch "$LOG_FILE" if [ ! "$CACHED_SOURCES" ]; then download_sources else if [ ! -f "$SRC_PATH/gcc/config.guess" ]; then arg_error "no sources found, run with --keep-artifacts first" fi fi change_dir "$SRC_PATH/gcc" BUILD=$(sh "./config.guess") execute "" "failed to download GCC dependencies" \ ./contrib/download_prerequisites for i in mpc isl mpfr gmp; do ln -s "$SRC_PATH/gcc/$i" "$SRC_PATH/binutils/$i" done export CFLAGS="-g0" export CXXFLAGS="-g0" export LDFLAGS="-s" ADD_TO_PATH=() if [ "$BUILD_I586" ]; then build i586 "$I586_PREFIX" ADD_TO_PATH+=("'$I586_PREFIX/bin'") fi if [ "$BUILD_I686" ]; then build i686 "$I686_PREFIX" ADD_TO_PATH+=("'$I686_PREFIX/bin'") fi if [ "$BUILD_X86_64" ]; then build x86_64 "$X86_64_PREFIX" ADD_TO_PATH+=("'$X86_64_PREFIX/bin'") fi if [ ! "$KEEP_ARTIFACTS" ]; then remove_path "$SRC_PATH" remove_path "$BLD_PATH" remove_path "$LOG_FILE" fi cat >${ROOT_PATH}/activate.sh <