#!/usr/bin/env bash # mingw-w64-build - download and build mingw-w64 toolchain # # Copyright 2020 Bradley Sepos # Released under the MIT License. See LICENSE for details. # https://github.com/bradleysepos/mingw-w64-build # checks for required external tools function check_dependencies { # check_dependencies $DEP1 $DEP2 ... local DEPS DEPS_EACH DEPS_MULTI ERRORS FOUND DEPS=("${@}"); ERRORS=() for DEPS_EACH in ${DEPS[@]}; do DEPS_MULTI=(${DEPS_EACH//|/ }) FOUND=false for DEP in ${DEPS_MULTI[@]}; do if echo "${DEP}" | grep '/' >/dev/null 2>&1 && [[ -x "${DEP}" ]]; then FOUND=true break elif hash "${DEP}" >/dev/null 2>&1; then FOUND=true break fi done if [[ "${FOUND}" == false ]]; then ERRORS+=("$(echo ${DEPS_MULTI[@]} | sed 's/ /|/')") fi done if [[ "${#ERRORS[@]}" -ne 0 ]]; then echo "dependencies: ${DEPS[@]}" echo "unable to find command(s): ${ERRORS[*]}" >&2 return 1 fi } # downloads from one or more urls function download_url { # download_url $VERBOSE $FILE $URLS local VERBOSE FILE URLS I FAILED OPTIND=1 VERBOSE="${1}" FILE="${2}" shift 2 URLS=("${@}") if [[ "${#URLS[@]}" -eq 0 ]] || [[ "${URLS[0]:-}" == "" ]]; then echo "url not specified for download" >&2 return 1 fi if [[ "${FILE:-}" == "" ]]; then echo "output path not specified for download: ${FILE}" >&2 return 1 fi FAILED=() for I in "${!URLS[@]}"; do if ! touch "${FILE}" >/dev/null 2>&1; then echo "unable to create path: ${FILE}" >&2 return 1 fi if [[ "${VERBOSE:-}" == true ]]; then echo "curl -Lf --connect-timeout 30 \"${URLS[I]}\" -o \"${FILE}\"" fi if ! curl -Lf --connect-timeout 30 "${URLS[I]}" -o "${FILE}" >/dev/null 2>&1; then FAILED+=("${URLS[I]}") if [[ "$(( ${I} + 1 ))" -lt "${#URLS[@]}" ]]; then continue else echo "unable to download from urls: ${FAILED[@]}" >&2 echo "unable to download to file: ${FILE}" >&2 return 1 fi fi return 0 done } # prints continuous output to avoid timeouts on build systems like Travis function display_progress { local str="" while [ "$(ps a | awk '{print $1}' | grep ${1})" ]; do printf "%c" "$str" sleep 5 str="." done } # kills child processes function die_gracefully { trap - EXIT INT trap ":" INT # prevent recursion due to spamming ctrl-c echo "" trap - TERM && kill -- -$$ } # tests whether a string is an exact match for an array item function in_array { # in_array needle haystack[@] local e for e in "${@:2}"; do [[ "${e}" == "${1}" ]] && return 0 done return 1 } # builds mingw-w64 function mingw-w64-build { # mingw-w64-build [args] $TARGET_PARAM $TARGET_DIR set -o pipefail # package names local CONFIG_NAME BINUTILS_NAME MINGW_W64_NAME GMP_NAME MPFR_NAME MPC_NAME ISL_NAME GCC_NAME GDB_NAME NAMES CONFIG_NAME="config" BINUTILS_NAME="binutils" MINGW_W64_NAME="mingw-w64" GMP_NAME="gmp" MPFR_NAME="mpfr" MPC_NAME="mpc" ISL_NAME="isl" GCC_NAME="gcc" NAMES=("${CONFIG_NAME}" "${BINUTILS_NAME}" "${MINGW_W64_NAME}" "${GMP_NAME}" "${MPFR_NAME}" "${MPC_NAME}" "${ISL_NAME}" "${GCC_NAME}") # versions local CONFIG_VER BINUTILS_VER MINGW_W64_VER GMP_VER MPFR_VER MPC_VER ISL_VER GCC_VER GDB_VER VERSIONS CONFIG_VER="77632d9" # config.guess 2020-11-07 BINUTILS_VER="2.35.1" MINGW_W64_VER="8.0.0" GMP_VER="6.2.0" MPFR_VER="4.1.0" MPC_VER="1.2.1" ISL_VER="0.22.1" GCC_VER="10.2.0" VERSIONS=("${CONFIG_VER}" "${BINUTILS_VER}" "${MINGW_W64_VER}" "${GMP_VER}" "${MPFR_VER}" "${MPC_VER}" "${ISL_VER}" "${GCC_VER}") # filenames local CONFIG_PKG BINUTILS_PKG MINGW_W64_PKG GMP_PKG MPFR_PKG MPC_PKG ISL_PKG GCC_PKG GDB_PKG PKGS CONFIG_PKG="config-${CONFIG_VER}.tar.gz" BINUTILS_PKG="binutils-${BINUTILS_VER}.tar.bz2" MINGW_W64_PKG="mingw-w64-v${MINGW_W64_VER}.tar.bz2" GMP_PKG="gmp-${GMP_VER}.tar.bz2" MPFR_PKG="mpfr-${MPFR_VER}.tar.gz" MPC_PKG="mpc-${MPC_VER}.tar.gz" ISL_PKG="isl-${ISL_VER}.tar.bz2" GCC_PKG="gcc-${GCC_VER}.tar.gz" PKGS=("${CONFIG_PKG}" "${BINUTILS_PKG}" "${MINGW_W64_PKG}" "${GMP_PKG}" "${MPFR_PKG}" "${MPC_PKG}" "${ISL_PKG}" "${GCC_PKG}") # urls local CONFIG_URLS BINUTILS_URLS MINGW_W64_URLS GMP_URLS MPFR_URLS MPC_URLS ISL_URLS GCC_URLS GDB_URLS URLS_VARNAMES ARCHIVE_URL ARCHIVE_URL="https://github.com/bradleysepos/mingw-w64-build-deps/releases/download/archive" CONFIG_URLS=("https://git.savannah.gnu.org/gitweb/?p=config.git;a=snapshot;h=${CONFIG_VER};sf=tgz" "${ARCHIVE_URL}/${CONFIG_PKG}") BINUTILS_URLS=("https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VER}.tar.bz2" "${ARCHIVE_URL}/${BINUTILS_PKG}") MINGW_W64_URLS=("http://downloads.sourceforge.net/project/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v${MINGW_W64_VER}.tar.bz2" "${ARCHIVE_URL}/${MINGW_W64_PKG}") GMP_URLS=("https://ftp.gnu.org/gnu/gmp/gmp-${GMP_VER}.tar.bz2" "${ARCHIVE_URL}/${GMP_PKG}") MPFR_URLS=("https://ftp.gnu.org/gnu/mpfr/mpfr-${MPFR_VER}.tar.gz" "${ARCHIVE_URL}/${MPFR_PKG}") MPC_URLS=("https://ftp.gnu.org/gnu/mpc/mpc-${MPC_VER}.tar.gz" "${ARCHIVE_URL}/${MPC_PKG}") ISL_URLS=("http://isl.gforge.inria.fr/isl-${ISL_VER}.tar.bz2" "${ARCHIVE_URL}/${ISL_PKG}") GCC_URLS=("https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.gz" "${ARCHIVE_URL}/${GCC_PKG}") URLS_VARNAMES=('CONFIG_URLS' 'BINUTILS_URLS' 'MINGW_W64_URLS' 'GMP_URLS' 'MPFR_URLS' 'MPC_URLS' 'ISL_URLS' 'GCC_URLS') # checksums local CONFIG_SHA256 BINUTILS_SHA256 MINGW_W64_SHA256 GMP_SHA256 MPFR_SHA256 MPC_SHA256 ISL_SHA256 GCC_SHA256 GDB_SHA256 CHECKSUMS CONFIG_SHA256="74a9d78c80258ae18e275c272056d6a7f606230c029890c614fa805ea44bb0bf" BINUTILS_SHA256="320e7a1d0f46fcd9f413f1046e216cbe23bb2bce6deb6c6a63304425e48b1942" MINGW_W64_SHA256="44c740ea6ab3924bc3aa169bad11ad3c5766c5c8459e3126d44eabb8735a5762" GMP_SHA256="f51c99cb114deb21a60075ffb494c1a210eb9d7cb729ed042ddb7de9534451ea" MPFR_SHA256="3127fe813218f3a1f0adf4e8899de23df33b4cf4b4b3831a5314f78e65ffa2d6" MPC_SHA256="17503d2c395dfcf106b622dc142683c1199431d095367c6aacba6eec30340459" ISL_SHA256="1a668ef92eb181a7c021e8531a3ca89fd71aa1b3744db56f68365ab0a224c5cd" GCC_SHA256="27e879dccc639cd7b0cc08ed575c1669492579529b53c9ff27b0b96265fa867d" CHECKSUMS=("${CONFIG_SHA256}" "${BINUTILS_SHA256}" "${MINGW_W64_SHA256}" "${GMP_SHA256}" "${MPFR_SHA256}" "${MPC_SHA256}" "${ISL_SHA256}" "${GCC_SHA256}") # internal vars local NAME VERSION SELF SELF_NAME HELP NAME="mingw-w64-build" VERSION="9.2.0" SELF="${BASH_SOURCE[0]}" SELF_NAME=$(basename "${SELF}") HELP="\ ${NAME} ${VERSION} usage: ${SELF_NAME} [-h | --help] ${SELF_NAME} [-l | --list] ${SELF_NAME} [-v | --version] ${SELF_NAME} [-f | --force] [-j # | --jobs #] [--disable-gdb] target [install-dir] where: -h, --help display this help text -l, --list display components list -v, --version display version information -f, --force remove and replace existing target (overwrite) -j, --jobs number of concurrent build jobs to run default: 0 (automatic) --disable-gdb disable building GDB debugger targets: i686 i686.clean i686.distclean x86_64 x86_64.clean x86_64.distclean pkgclean default install-dir: ${HOME}/toolchains/mingw-w64-${MINGW_W64_VER}-gcc-${GCC_VER}" # args local FORCE JOBS LIST DISABLE_GDB OPTIND OPTSPEC OPTARRAY FORCE=false JOBS=0 LIST=false DISABLE_GDB=false OPTIND=1 OPTSPEC=":-:hlvfj:" OPTARRAY=('-h' '--help' '-l' '--list' '-v' '--version' '--force' '-j' '--jobs' '--disable-gdb') # all short and long options while getopts "${OPTSPEC}" OPT; do case "${OPT}" in -) case "${OPTARG}" in help) # Print help and exit echo -e "${HELP}" return 0 ;; help=*) # Print help and exit echo -e "${HELP}" return 0 ;; list) # List components LIST=true ;; list=*) # List components LIST=true ;; version) # Print version and exit echo -e "${NAME} ${VERSION}" return 0 ;; version=*) # Print version and exit echo -e "${NAME} ${VERSION}" return 0 ;; force) # Force remove and replace dist (overwrite) FORCE=true ;; force=*) # Option with prohibited value echo "Option --${OPTARG%%=*} takes no value" >&2 echo -e "${HELP}" return 1 ;; jobs) # Number of jobs if [[ -z ${!OPTIND+isset} ]] || in_array "${!OPTIND}" "${OPTARRAY[@]}"; then # Option without required argument echo "Option --${OPTARG} requires a value" >&2 echo -e "${HELP}" return 1 fi JOBS="${!OPTIND}" if [[ ! "${JOBS}" =~ ^[0-9]*$ ]]; then echo "Option --${OPTARG} requires a numeric value" >&2 echo -e "${HELP}" return 1 fi OPTIND=$((OPTIND + 1)) ;; jobs=*) # Number of jobs JOBS="${OPTARG#*=}" if [[ ! "${JOBS}" =~ ^[0-9]*$ ]]; then echo "Option --${OPTARG} requires a numeric value" >&2 echo -e "${HELP}" return 1 fi ;; disable-gdb) # Disable GDB DISABLE_GDB=true ;; *) if [[ "${OPTERR}" == 1 ]]; then # Invalid option specified echo "Invalid option: --${OPTARG}" >&2 echo -e "${HELP}" return 1 fi ;; esac ;; h) # Print help and exit echo -e "${HELP}" return 0 ;; l) # List components LIST=true ;; v) # Print version and exit echo "${NAME} ${VERSION}" return 0 ;; f) # Force remove and replace dist (overwrite) FORCE=true ;; j) # Number of jobs JOBS="${OPTARG}" if [[ ! "${JOBS}" =~ ^[0-9]*$ ]]; then echo "Option -${OPT} requires a numeric value" >&2 echo -e "${HELP}" return 1 fi ;; :) # Option without required value echo "Option -${OPTARG} requires a value" >&2 echo -e "${HELP}" return 1 ;; \?) # Invalid option specified echo "Invalid option: -${OPTARG}" >&2 echo -e "${HELP}" return 1 ;; esac done shift $((OPTIND - 1)) # gdb? if [[ "${DISABLE_GDB}" == false ]] || [[ "${LIST}" == true ]]; then GDB_NAME="gdb" NAMES+=("${GDB_NAME}") GDB_VER="10.1" VERSIONS+=("${GDB_VER}") GDB_PKG="gdb-${GDB_VER}.tar.gz" PKGS+=("${GDB_PKG}") GDB_URLS=("https://ftp.gnu.org/gnu/gdb/gdb-${GDB_VER}.tar.gz" "${ARCHIVE_URL}/${GDB_PKG}") URLS_VARNAMES+=('GDB_URLS') GDB_SHA256="f12f388b99e1408c01308c3f753313fafa45517740c81ab7ed0d511b13e2cf55" CHECKSUMS+=("${GDB_SHA256}") fi # host local SYS_NAME SYS_ARCH CPU_COUNT SYS_NAME=$(uname | awk '{ print tolower($0)}') SYS_ARCH=$(uname -m) if [[ "${SYS_NAME}" == "darwin" ]]; then CPU_COUNT=$(sysctl -n hw.activecpu 2>/dev/null) elif [[ "${SYS_NAME}" == "linux" ]]; then CPU_COUNT=$(grep -c processor /proc/cpuinfo 2>/dev/null) fi CPU_COUNT="${CPU_COUNT:-1}" [[ "${JOBS}" -eq 0 ]] && JOBS="${CPU_COUNT}" # begin output echo "${NAME} ${VERSION} (${JOBS} job$([[ ${JOBS} -gt 1 ]] && echo 's'))" # list components if [[ "${LIST}" == true ]]; then local COMPONENTS COMPONENTS_TEMP COMPONENTS_TEMP=() for I in "${!NAMES[@]}"; do COMPONENTS_TEMP+=("${NAMES[$I]} ${VERSIONS[$I]}") done COMPONENTS_TEMP+=('winpthreads') OIFS="${IFS}" IFS=$'\n' COMPONENTS=($(sort <<< "${COMPONENTS_TEMP[*]}")) IFS="${OIFS}" echo "Components:" for I in "${!COMPONENTS[@]}"; do echo " ${COMPONENTS[$I]}" done return 0 fi # dependencies local DEPS DEPS=("bison" "bzip2" "curl" "flex" "g++" "gcc" "gunzip" "m4" "make" "pax" "shasum|sha256sum") check_dependencies "${DEPS[@]}" || return 1 # sha256 binary local SHA256 if hash shasum >/dev/null 2>&1; then SHA256="shasum -a 256" elif hash sha256sum >/dev/null 2>&1; then SHA256="sha256sum" else return 1 fi # target args local TARGET_PARAM TARGET_DIR TARGET_i686 TARGET_x86_64 PREFIX_i686 PREFIX_x86_64 TARGET PREFIX TARGET_PARAM="${1}" TARGET_DIR="${2}" TARGET_i686="i686-w64-mingw32" TARGET_x86_64="x86_64-w64-mingw32" PREFIX_i686="mingw-w64-i686" PREFIX_x86_64="mingw-w64-x86_64" if [[ "${TARGET_PARAM:-}" == "" ]]; then echo -e "${HELP}" echo "no target specified" >&2 return 1 fi case "${TARGET_PARAM}" in i686|i686.clean|i686.distclean) TARGET="${TARGET_i686}" PREFIX="${PREFIX_i686}" ;; x86_64|x86_64.clean|x86_64.distclean) TARGET="${TARGET_x86_64}" PREFIX="${PREFIX_x86_64}" ;; pkgclean) TARGET="pkgclean" PREFIX="pkgclean" ;; esac if [[ "${PREFIX:-}" == "" ]]; then echo -e "${HELP}" echo "target not valid: ${TARGET_PARAM}" >&2 return 1 fi if [[ "${TARGET_DIR:-}" == "" ]]; then TARGET_DIR="${HOME}/toolchains/mingw-w64-${MINGW_W64_VER}-gcc-${GCC_VER}" fi # create target directory mkdir -p "${TARGET_DIR}" if [[ ! -d "${TARGET_DIR}" ]]; then echo "unable to create directory: ${TARGET_DIR}" >&2 return 1 fi # directories local BASE_DIR MINGW_W64_DIR PKG_DIR SOURCE_DIR BUILD_DIR LOG_DIR BASE_DIR=$(pwd) cd "${TARGET_DIR}" TARGET_DIR=$(pwd) cd "${BASE_DIR}" MINGW_W64_DIR="${TARGET_DIR}/${PREFIX}" PKG_DIR="${TARGET_DIR}/pkg" SOURCE_DIR="${TARGET_DIR}/source.noindex" BUILD_DIR="${TARGET_DIR}/build-${PREFIX}.noindex" LOG_DIR="${BUILD_DIR}" # clean case "${TARGET_PARAM}" in i686.clean|x86_64.clean) echo "rm -rf \"${BUILD_DIR}\" " echo "rm -rf \"${SOURCE_DIR}\" " rm -rf "${BUILD_DIR}" rm -rf "${SOURCE_DIR}" return 0 ;; i686.distclean|x86_64.distclean) echo "rm -rf \"${MINGW_W64_DIR}\" " rm -rf "${MINGW_W64_DIR}" return 0 ;; pkgclean) echo "rm -rf \"${PKG_DIR}\" " rm -rf "${PKG_DIR}" return 0 ;; esac # remove non-reusable directories local CLEAN_INDEX CLEAN_TOTAL CLEAN_INDEX=0 CLEAN_TOTAL=2 if [[ "${FORCE}" == true ]]; then CLEAN_INDEX=$((CLEAN_INDEX+1)) CLEAN_TOTAL=$((CLEAN_TOTAL+1)) printf "Cleaning [%02i/%02i] dist " "${CLEAN_INDEX}" "${CLEAN_TOTAL}" rm -rf "${MINGW_W64_DIR}" echo "" elif [[ -e "${MINGW_W64_DIR}" ]]; then # prefix dir should not exist echo "unable to create directory (exists): ${MINGW_W64_DIR}" >&2 echo "remove with: ${SELF_NAME} ${TARGET_PARAM%%.*}.distclean${2:+ $2}" >&2 return 1 fi CLEAN_INDEX=$((CLEAN_INDEX+1)) printf "Cleaning [%02i/%02i] source " "${CLEAN_INDEX}" "${CLEAN_TOTAL}" rm -rf "${SOURCE_DIR}" CLEAN_INDEX=$((CLEAN_INDEX+1)) echo "" printf "Cleaning [%02i/%02i] build " "${CLEAN_INDEX}" "${CLEAN_TOTAL}" rm -rf "${BUILD_DIR}" # verify/fetch mkdir -p "${PKG_DIR}" if [[ ! -d "${PKG_DIR}" ]]; then echo "unable to create directory: ${PKG_DIR}" >&2 return 1 fi local DOWNLOAD_VERBOSE I URLS_IREF URLS CHECKSUM DOWNLOAD_VERBOSE=false for I in "${!PKGS[@]}"; do echo "" printf "Downloading [%02i/%02i] %s " "$((I+1))" "${#PKGS[@]}" "${NAMES[I]} ${VERSIONS[I]}" URLS_IREF="${URLS_VARNAMES[I]}[@]" URLS="${!URLS_IREF}" CHECKSUM=$(${SHA256} "${PKG_DIR}/${PKGS[I]}" 2>/dev/null | awk '{ print $1 }') if [[ "${CHECKSUM}" != "${CHECKSUMS[I]}" ]] >/dev/null 2>&1; then download_url "${DOWNLOAD_VERBOSE}" "${PKG_DIR}/${PKGS[I]}" ${URLS[@]} || return 1 fi CHECKSUM=$(${SHA256} "${PKG_DIR}/${PKGS[I]}" 2>/dev/null | awk '{ print $1 }') if [[ "${CHECKSUM}" != "${CHECKSUMS[I]}" ]]; then echo "checksum mismatch for package: ${PKG_DIR}/${PKGS[I]}" >&2 echo "expected: ${CHECKSUMS[I]}" >&2 echo "actual: ${CHECKSUM}" >&2 return 1 fi done # extract mkdir -p "${SOURCE_DIR}" if [[ ! -d "${SOURCE_DIR}" ]]; then echo "unable to create directory: ${SOURCE_DIR}" >&2 return 1 fi for I in "${!PKGS[@]}"; do echo "" printf "Extracting [%02i/%02i] %s " "$((I+1))" "${#PKGS[@]}" "${PKGS[I]}" if [[ -e "${SOURCE_DIR}/${NAMES[I]}" ]]; then rm -rf "${SOURCE_DIR}/${NAMES[I]}" fi mkdir -p "${SOURCE_DIR}/${NAMES[I]}" if ! tar -xf "${PKG_DIR}/${PKGS[I]}" -C "${SOURCE_DIR}/${NAMES[I]}" >/dev/null 2>&1; then if ! unzip -d "${SOURCE_DIR}/${NAMES[I]}" "${PKG_DIR}/${PKGS[I]}" >/dev/null 2>&1; then echo "unable to extract package: ${PKG_DIR}/${PKGS[I]}" >&2 return 1 fi fi done # create build and prefix directories mkdir -p "${BUILD_DIR}" if [[ ! -d "${BUILD_DIR}" ]]; then echo "unable to create directory: ${BUILD_DIR}" >&2 return 1 fi mkdir -p "${MINGW_W64_DIR}" if [[ ! -d "${MINGW_W64_DIR}" ]]; then echo "unable to create directory: ${MINGW_W64_DIR}" >&2 return 1 fi # build local SYS_TYPE TOTAL SYS_TYPE=$("${SOURCE_DIR}/config/config-${CONFIG_VER}/config.guess") TOTAL=11 if [[ "${DISABLE_GDB}" == true ]]; then TOTAL="$((${TOTAL} - 1))" fi # binutils echo "" printf "Building [%02i/%02i] %s " "1" "${TOTAL}" "binutils ${BINUTILS_VER}" touch "${LOG_DIR}/binutils.log" mkdir -pv "${BUILD_DIR}/binutils" > "${LOG_DIR}/binutils.log" 2>&1 || return 1 cd "${BUILD_DIR}/binutils" "${SOURCE_DIR}/binutils/binutils-${BINUTILS_VER}/configure" CC=gcc CXX=g++ --build="${SYS_TYPE}" --target="${TARGET}" --with-sysroot="${MINGW_W64_DIR}" --prefix="${MINGW_W64_DIR}" --disable-multilib --disable-nls --disable-werror --enable-lto --disable-shared --enable-static >> "${LOG_DIR}/binutils.log" 2>&1 || return 1 make -j "${JOBS}" MAKEINFO=true >> "${LOG_DIR}/binutils.log" 2>&1 || return 1 make install-strip MAKEINFO=true >> "${LOG_DIR}/binutils.log" 2>&1 || return 1 # update PATH export PATH="${MINGW_W64_DIR}/bin:${PATH}" # mingw-w64 headers echo "" printf "Building [%02i/%02i] %s " "2" "${TOTAL}" "mingw-w64 ${MINGW_W64_VER} headers" touch "${LOG_DIR}/mingw-w64-headers.log" mkdir -pv "${BUILD_DIR}/mingw-w64-headers" > "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1 cd "${BUILD_DIR}/mingw-w64-headers" "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-headers/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}" >> "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1 make install-strip >> "${LOG_DIR}/mingw-w64-headers.log" 2>&1 || return 1 # create symlinks cd "${MINGW_W64_DIR}" ln -s "${TARGET}" mingw if [[ ! -d "usr" ]]; then ln -s . usr fi if [[ ! -d "${TARGET}/include" ]]; then cd "${TARGET}" ln -s ../include include cd "${MINGW_W64_DIR}" fi if [[ ! -d "${TARGET}/usr" ]]; then cd "${TARGET}" ln -s . usr cd "${MINGW_W64_DIR}" fi # gmp echo "" printf "Building [%02i/%02i] %s " "3" "${TOTAL}" "gmp ${GMP_VER}" touch "${LOG_DIR}/gmp.log" local GMP_DIR GMP_DIR="${BUILD_DIR}/gmp-${GMP_VER}-${SYS_ARCH}" mkdir -pv "${BUILD_DIR}/gmp" > "${LOG_DIR}/gmp.log" 2>&1 || return 1 cd "${BUILD_DIR}/gmp" "${SOURCE_DIR}/gmp/gmp-${GMP_VER}/configure" CC=gcc CXX=g++ CPPFLAGS=-fexceptions --build="${SYS_TYPE}" --prefix="${GMP_DIR}" --enable-cxx --disable-shared --enable-static >> "${LOG_DIR}/gmp.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/gmp.log" 2>&1 || return 1 make check >> "${LOG_DIR}/gmp.log" 2>&1 || return 1 make install >> "${LOG_DIR}/gmp.log" 2>&1 || return 1 # mpfr echo "" printf "Building [%02i/%02i] %s " "4" "${TOTAL}" "mpfr ${MPFR_VER}" touch "${LOG_DIR}/mpfr.log" local MPFR_DIR MPFR_DIR="${BUILD_DIR}/mpfr-${MPFR_VER}-${SYS_ARCH}" mkdir -pv "${BUILD_DIR}/mpfr" > "${LOG_DIR}/mpfr.log" 2>&1 || return 1 cd "${BUILD_DIR}/mpfr" "${SOURCE_DIR}/mpfr/mpfr-${MPFR_VER}/configure" CC=gcc CXX=g++ CFLAGS="-I${GMP_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib" --build="${SYS_TYPE}" --prefix="${MPFR_DIR}" --with-gmp="${GMP_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/mpfr.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/mpfr.log" 2>&1 || return 1 make install >> "${LOG_DIR}/mpfr.log" 2>&1 || return 1 # mpc echo "" printf "Building [%02i/%02i] %s " "5" "${TOTAL}" "mpc ${MPC_VER}" touch "${LOG_DIR}/mpc.log" local MPC_DIR MPC_DIR="${BUILD_DIR}/mpc-${MPC_VER}-${SYS_ARCH}" mkdir -pv "${BUILD_DIR}/mpc" > "${LOG_DIR}/mpc.log" 2>&1 || return 1 cd "${BUILD_DIR}/mpc" "${SOURCE_DIR}/mpc/mpc-${MPC_VER}/configure" CC=gcc CXX=g++ CFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib -L${MPFR_DIR}/lib" --build="${SYS_TYPE}" --prefix="${MPC_DIR}" --with-gmp="${GMP_DIR}" --with-mpfr="${MPFR_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/mpc.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/mpc.log" 2>&1 || return 1 make install >> "${LOG_DIR}/mpc.log" 2>&1 || return 1 # isl echo "" printf "Building [%02i/%02i] %s " "6" "${TOTAL}" "isl ${ISL_VER}" touch "${LOG_DIR}/isl.log" local ISL_DIR ISL_DIR="${BUILD_DIR}/isl-${ISL_VER}-${SYS_ARCH}" mkdir -pv "${BUILD_DIR}/isl" > "${LOG_DIR}/isl.log" 2>&1 || return 1 cd "${BUILD_DIR}/isl" "${SOURCE_DIR}/isl/isl-${ISL_VER}/configure" CC=gcc CXX=g++ CFLAGS="-I${GMP_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib" --build="${SYS_TYPE}" --prefix="${ISL_DIR}" --with-gmp="${GMP_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/isl.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/isl.log" 2>&1 || return 1 make install >> "${LOG_DIR}/isl.log" 2>&1 || return 1 # gcc compilers echo "" printf "Building [%02i/%02i] %s " "7" "${TOTAL}" "gcc ${GCC_VER} compilers" touch "${LOG_DIR}/gcc.log" local GCC_CONFIG_EXTRA GCC_CONFIG_EXTRA=() if [[ "${SYS_NAME}" == "darwin" ]]; then GCC_CONFIG_EXTRA+=("--with-system-zlib") fi mkdir -pv "${BUILD_DIR}/gcc" > "${LOG_DIR}/gcc.log" 2>&1 || return 1 cd "${BUILD_DIR}/gcc" "${SOURCE_DIR}/gcc/gcc-${GCC_VER}/configure" CFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include -I${MPC_DIR}/include -I${ISL_DIR}/include" CPPFLAGS="-I${GMP_DIR}/include -I${MPFR_DIR}/include -I${MPC_DIR}/include -I${ISL_DIR}/include" LDFLAGS="-L${GMP_DIR}/lib -L${MPFR_DIR}/lib -L${MPC_DIR}/lib -L${ISL_DIR}/lib" --build="${SYS_TYPE}" --host="${SYS_TYPE}" --target="${TARGET}" --prefix="${MINGW_W64_DIR}" --with-sysroot="${MINGW_W64_DIR}" --with-gmp="${GMP_DIR}" --with-mpfr="${MPFR_DIR}" --with-mpc="${MPC_DIR}" --with-isl="${ISL_DIR}" --disable-multilib --disable-nls --disable-libstdcxx-pch --disable-win32-registry --enable-checking=release --enable-languages=c,c++ --enable-lto --disable-shared --enable-static "${GCC_CONFIG_EXTRA[@]}" >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 make -j "${JOBS}" all-gcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 make install-strip-gcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 # mingw-w64 runtime echo "" printf "Building [%02i/%02i] %s " "8" "${TOTAL}" "mingw-w64 ${MINGW_W64_VER} runtime" touch "${LOG_DIR}/mingw-w64-crt.log" export CC="" export CXX="" local MINGW_W64_CONFIG_EXTRA MINGW_W64_CONFIG_EXTRA=() if [[ "${TARGET}" == "${TARGET_i686}" ]]; then MINGW_W64_CONFIG_EXTRA+=("--enable-lib32" "--disable-lib64") elif [[ "${TARGET}" == "${TARGET_x86_64}" ]]; then MINGW_W64_CONFIG_EXTRA+=("--enable-lib64" "--disable-lib32") fi mkdir -pv "${BUILD_DIR}/mingw-w64-crt" > "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1 cd "${BUILD_DIR}/mingw-w64-crt" "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-crt/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}" --with-sysroot="${MINGW_W64_DIR}" "${MINGW_W64_CONFIG_EXTRA[@]}" >> "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1 make install-strip >> "${LOG_DIR}/mingw-w64-crt.log" 2>&1 || return 1 # relocate and symlink libs cd "${MINGW_W64_DIR}" mv "${TARGET}/lib/"* lib/ rm -rf "${TARGET}/lib" cd "${TARGET}" ln -s ../lib lib # gcc libraries echo "" printf "Building [%02i/%02i] %s " "9" "${TOTAL}" "gcc ${GCC_VER} libraries" touch "${LOG_DIR}/gcc.log" cd "${BUILD_DIR}/gcc" make -j "${JOBS}" all-target-libgcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 make -j "${JOBS}" install-target-libgcc >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 make install-strip >> "${LOG_DIR}/gcc.log" 2>&1 || return 1 # winpthreads echo "" printf "Building [%02i/%02i] %s " "10" "${TOTAL}" "winpthreads" touch "${LOG_DIR}/winpthreads.log" mkdir -pv "${BUILD_DIR}/winpthreads" > "${LOG_DIR}/winpthreads.log" 2>&1 || return 1 cd "${BUILD_DIR}/winpthreads" "${SOURCE_DIR}/mingw-w64/mingw-w64-v${MINGW_W64_VER}/mingw-w64-libraries/winpthreads/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}" --disable-shared --enable-static >> "${LOG_DIR}/winpthreads.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/winpthreads.log" 2>&1 || return 1 make install-strip >> "${LOG_DIR}/winpthreads.log" 2>&1 || return 1 # gdb if [[ "${DISABLE_GDB}" == false ]]; then echo "" printf "Building [%02i/%02i] %s " "11" "${TOTAL}" "gdb" touch "${LOG_DIR}/gdb.log" mkdir -pv "${BUILD_DIR}/gdb" > "${LOG_DIR}/gdb.log" 2>&1 || return 1 cd "${BUILD_DIR}/gdb" # https://sourceware.org/bugzilla/show_bug.cgi?id=18113 echo '#!/bin/sh' > makeinfo echo 'echo "makeinfo (GNU texinfo) 5.2"' >> makeinfo chmod a+x makeinfo "${SOURCE_DIR}/gdb/gdb-${GDB_VER}/configure" --build="${SYS_TYPE}" --host="${TARGET}" --prefix="${MINGW_W64_DIR}" -disable-multilib --enable-checking=release --enable-languages=c,c++ --enable-lto --disable-shared --enable-static MAKEINFO="${BUILD_DIR}/gdb/makeinfo" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1 make -j "${JOBS}" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1 make install >> "${LOG_DIR}/gdb.log" 2>&1 || return 1 "${TARGET}"-strip "${MINGW_W64_DIR}/bin/gdb.exe" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1 "${TARGET}"-strip "${MINGW_W64_DIR}/bin/gdbserver.exe" >> "${LOG_DIR}/gdb.log" 2>&1 || return 1 fi # clean up cd "${MINGW_W64_DIR}" find . -name "*.la" -type f -exec rm {} ";" >/dev/null 2>&1 # done echo "" echo " run the following command and add it to your shell startup script" echo " (e.g., .bashrc or .bash_profile) to make persistent across sessions:" echo " export PATH=\"${MINGW_W64_DIR}/bin:\${PATH}\"" echo "Complete." return 0 set +o pipefail } trap die_gracefully EXIT INT TERM mingw-w64-build "${@}" & PID=$! display_progress "${PID}" wait "${PID}" || CODE=$? trap - EXIT INT TERM if [[ "${CODE}" -ne 0 ]]; then PARAMS=() for PARAM in "${@}"; do if [[ "${PARAM#-}" != "${PARAM}" ]]; then continue fi PARAMS+=("${PARAM}") done TDIR="${PARAMS[1]}" echo "" echo "error: subprocess returned non-zero error code (${CODE})" >&2 echo "logs and temporary files may exist at ${TDIR:-$HOME/toolchains}" >&2 exit 1 fi exit 0