mirror of https://github.com/HandBrake/HandBrake
811 lines
32 KiB
Bash
Executable File
811 lines
32 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# mingw-w64-build - download and build mingw-w64 toolchain
|
|
#
|
|
# Copyright 2025 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"
|
|
GDB_NAME="gdb"
|
|
|
|
# versions
|
|
local CONFIG_VER BINUTILS_VER MINGW_W64_VER GMP_VER MPFR_VER MPC_VER ISL_VER GCC_VER GDB_VER VERSIONS
|
|
CONFIG_VER="e478644" # config.guess 2023-08-22
|
|
BINUTILS_VER="2.41"
|
|
MINGW_W64_VER="11.0.1"
|
|
GMP_VER="6.3.0"
|
|
MPFR_VER="4.2.1"
|
|
MPC_VER="1.3.1"
|
|
ISL_VER="0.26"
|
|
GCC_VER="13.2.0"
|
|
GDB_VER="14.0.91"
|
|
|
|
# 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"
|
|
GDB_PKG="gdb-${GDB_VER}.tar.gz"
|
|
|
|
# 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=("https://libisl.sourceforge.io/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}")
|
|
#GDB_URLS=("https://ftp.gnu.org/gnu/gdb/gdb-${GDB_VER}.tar.gz" "${ARCHIVE_URL}/${GDB_PKG}")
|
|
GDB_URLS=("https://sourceware.org/pub/gdb/snapshots/branch/gdb-${GDB_VER}.tar.gz" "${ARCHIVE_URL}/${GDB_PKG}")
|
|
|
|
# checksums
|
|
local CONFIG_SHA256 BINUTILS_SHA256 MINGW_W64_SHA256 GMP_SHA256 MPFR_SHA256 MPC_SHA256 ISL_SHA256 GCC_SHA256 GDB_SHA256 CHECKSUMS
|
|
CONFIG_SHA256="5ff5d77fe5900690c150aa9ed59c6a4461279edccb906edfb34427cde05949df"
|
|
BINUTILS_SHA256="a4c4bec052f7b8370024e60389e194377f3f48b56618418ea51067f67aaab30b"
|
|
MINGW_W64_SHA256="3f66bce069ee8bed7439a1a13da7cb91a5e67ea6170f21317ac7f5794625ee10"
|
|
GMP_SHA256="ac28211a7cfb609bae2e2c8d6058d66c8fe96434f740cf6fe2e47b000d1c20cb"
|
|
MPFR_SHA256="116715552bd966c85b417c424db1bbdf639f53836eb361549d1f8d6ded5cb4c6"
|
|
MPC_SHA256="ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8"
|
|
ISL_SHA256="5eac8664e9d67be6bd0bee5085d6840b8baf738c06814df47eaf4166d9776436"
|
|
GCC_SHA256="8cb4be3796651976f94b9356fa08d833524f62420d6292c5033a9a26af315078"
|
|
GDB_SHA256="985261949c3dd03f3e689584539fc8e01b16fecb91a7eb7cae7396c74a5b5ca8"
|
|
|
|
# arrays of default components
|
|
NAMES=("${CONFIG_NAME}" "${BINUTILS_NAME}" "${MINGW_W64_NAME}" "${GMP_NAME}" "${MPFR_NAME}" "${MPC_NAME}" "${ISL_NAME}" "${GCC_NAME}")
|
|
VERSIONS=("${CONFIG_VER}" "${BINUTILS_VER}" "${MINGW_W64_VER}" "${GMP_VER}" "${MPFR_VER}" "${MPC_VER}" "${ISL_VER}" "${GCC_VER}")
|
|
PKGS=("${CONFIG_PKG}" "${BINUTILS_PKG}" "${MINGW_W64_PKG}" "${GMP_PKG}" "${MPFR_PKG}" "${MPC_PKG}" "${ISL_PKG}" "${GCC_PKG}")
|
|
URLS_VARNAMES=('CONFIG_URLS' 'BINUTILS_URLS' 'MINGW_W64_URLS' 'GMP_URLS' 'MPFR_URLS' 'MPC_URLS' 'ISL_URLS' 'GCC_URLS')
|
|
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="10.0.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 #] [--msvcrt runtime]
|
|
[--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)
|
|
--msvcrt
|
|
msvc runtime version (msvcrt or ucrt)
|
|
default: msvcrt
|
|
--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}-msvcrt-gcc-${GCC_VER}"
|
|
|
|
# args
|
|
local FORCE JOBS LIST DISABLE_GDB OPTIND OPTSPEC OPTARRAY
|
|
FORCE=false
|
|
JOBS=0
|
|
LIST=false
|
|
MSVCRT="msvcrt"
|
|
DISABLE_GDB=false
|
|
OPTIND=1
|
|
OPTSPEC=":-:hlvfj:"
|
|
OPTARRAY=('-h' '--help' '-l' '--list' '-v' '--version' '-f' '--force' '-j' '--jobs' '--msvcrt' '--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
|
|
;;
|
|
msvcrt)
|
|
# MSVC runtime
|
|
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
|
|
MSVCRT="${!OPTIND}"
|
|
if [[ "${MSVCRT}" != "msvcrt" ]] && [[ "${MSVCRT}" != "ucrt" ]]; then
|
|
echo "Option --${OPTARG} value must be msvcrt or ucrt" >&2
|
|
echo -e "${HELP}"
|
|
return 1
|
|
fi
|
|
OPTIND=$((OPTIND + 1))
|
|
;;
|
|
msvcrt=*)
|
|
# MSVC runtime
|
|
MSVCRT="${OPTARG#*=}"
|
|
if [[ "${MSVCRT}" != "msvcrt" ]] && [[ "${MSVCRT}" != "ucrt" ]]; then
|
|
echo "Option --${OPTARG} value must be msvcrt or ucrt" >&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))
|
|
|
|
# add optional components to arrays
|
|
if [[ "${DISABLE_GDB}" == false ]] || [[ "${LIST}" == true ]]; then
|
|
NAMES+=("${GDB_NAME}")
|
|
VERSIONS+=("${GDB_VER}")
|
|
PKGS+=("${GDB_PKG}")
|
|
URLS_VARNAMES+=('GDB_URLS')
|
|
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}-${MSVCRT}-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}" --with-default-msvcrt="${MSVCRT}" >> "${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}" --with-zstd=no --disable-multilib --disable-nls --disable-libstdcxx-pch --disable-win32-registry --enable-checking=release --enable-languages=c,c++ --enable-threads=posix --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-default-msvcrt="${MSVCRT}" --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
|
|
|
|
# winpthreads
|
|
echo ""
|
|
printf "Building [%02i/%02i] %s " "9" "${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
|
|
|
|
# gcc libraries
|
|
echo ""
|
|
printf "Building [%02i/%02i] %s " "10" "${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
|
|
|
|
# gdb
|
|
if [[ "${DISABLE_GDB}" == false ]]; then
|
|
echo ""
|
|
printf "Building [%02i/%02i] %s " "11" "${TOTAL}" "gdb ${GDB_VER}"
|
|
touch "${LOG_DIR}/gdb.log"
|
|
# create symlinks to gmp, mpfr, mpc, and isl for in-tree builds
|
|
cd "${SOURCE_DIR}/gdb/gdb-${GDB_VER}"
|
|
ln -s "../../gmp/gmp-${GMP_VER}" gmp > "${LOG_DIR}/gdb.log" 2>&1 || return 1
|
|
ln -s "../../mpfr/mpfr-${MPFR_VER}" mpfr > "${LOG_DIR}/gdb.log" 2>&1 || return 1
|
|
ln -s "../../mpc/mpc-${MPC_VER}" mpc > "${LOG_DIR}/gdb.log" 2>&1 || return 1
|
|
ln -s "../../isl/isl-${ISL_VER}" isl > "${LOG_DIR}/gdb.log" 2>&1 || return 1
|
|
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}" --with-zstd=no --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
|