diff options
author | Kyle Schwarz <zeranoe@gmail.com> | 2021-08-29 22:13:04 -0400 |
---|---|---|
committer | Kyle Schwarz <zeranoe@gmail.com> | 2021-08-29 22:13:04 -0400 |
commit | 73f3ddaabad202171ee89e032500f3de0458f9d2 (patch) | |
tree | 899cebee3f1ad00aeaa8bb0c9da8938b4310e048 | |
parent | 15801def126642e4e2d4e2220e0d344ed8f1239e (diff) |
Rewrite mingw-w64-build
Summary of changes:
* The build process has been moved out of the working directory and into
$HOME/.zeranoe/mingw-w64/src and $HOME/.zeranoe/mingw-w64/bld
* The output toolchain(s) are no longer installed to ./<arch>, but to
$HOME/.zeranoe/mingw-w64/<arch> or --prefix
* Switch to GCC's download_prerequisites for downloading ISL, GMP, MPFR,
and MPC
* Add numerous options, see --help
* Add progress reporting
* Update MinGW-w64, GCC, and Binutils default branches
* Clean up by default, removing the intermediate source, build, and log
files
-rw-r--r-- | README.md | 35 | ||||
-rwxr-xr-x | mingw-w64-build | 594 |
2 files changed, 395 insertions, 234 deletions
@@ -1,20 +1,27 @@ # mingw-w64-build -[MinGW-w64](https://mingw-w64.org) cross compiler build script for i686 (Win32) and x86_64 (Win64). +mingw-w64-build is a Bash script to build a [MinGW-w64](https://mingw-w64.org) +cross compiler for i686 (Win32) and x86_64 (Win64). It will build a fully static +toolchain that can compile Windows executables that don't depend on any GCC dll +files. -## Package -* [MinGW-w64](https://mingw-w64.org) 8git -* [Binutils](https://www.gnu.org/software/binutils/) 2.35git -* [GCC](https://gcc.gnu.org/) 10git -* [GMP](https://gmplib.org/) 6.2.1 -* [MPFR](http://www.mpfr.org/) 4.1.0 -* [MPC](http://www.multiprecision.org/mpc/) 1.2.1 -* [isl](http://isl.gforge.inria.fr/) 0.23 +## Default Branches +* [MinGW-w64](https://mingw-w64.org) v9.x +* [Binutils](https://www.gnu.org/software/binutils/) binutils-2_37-branch +* [GCC](https://gcc.gnu.org/) releases/gcc-11 -## Platforms -mingw-w64-build should run on Ubuntu, Cygwin, macOS (with Homebrew), and other Bash based shells. +## Default Prefix +`$HOME/.zeranoe/mingw-w64/i686` and `$HOME/.zeranoe/mingw-w64/x86_64` are the +default install locations, but this location can be modified with the `--prefix` +option. To ensure the new compilers are available system-wide, add +`$HOME/.zeranoe/mingw-w64/<arch>/bin` to the `$PATH`. -## License -mingw-w64-build is licensed under the GNU GPL 3.0 or later. A copy of the license can be found in the LICENSE file. +## Platforms +mingw-w64-build should run on Ubuntu, Cygwin, macOS (with Homebrew), and other +Bash based shells. ## Usage -See `mingw-w64-build --help` for build options. +See `mingw-w64-build --help` for all build options. + +## License +mingw-w64-build is licensed under the GNU GPL 3.0 or later. A copy of the +license can be found in the LICENSE file. diff --git a/mingw-w64-build b/mingw-w64-build index 93f2a9e..8b2ff39 100755 --- a/mingw-w64-build +++ b/mingw-w64-build @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (C) 2020 Kyle Schwarz +# Copyright (C) 2021 Kyle Schwarz <zeranoe@gmail.com> # # 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 @@ -16,261 +16,415 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -v_script="4git" -v_mingww64="8git" -v_binutils="2.35git" -v_gcc="10git" -v_gmp="6.2.1" -v_mpfr="4.1.0" -v_mpc="1.2.1" -v_isl="0.23" +ROOT_PATH="$HOME/.zeranoe/mingw-w64" +SRC_PATH="$ROOT_PATH/src" +BLD_PATH="$ROOT_PATH/bld" +LOG_FILE="$ROOT_PATH/build.log" +I686_PREFIX="$ROOT_PATH/i686" +X86_64_PREFIX="$ROOT_PATH/x86_64" + +MINGW_W64_BRANCH="v9.x" +BINUTILS_BRANCH="binutils-2_37-branch" +GCC_BRANCH="releases/gcc-11" + +ENABLE_THREADS="--enable-threads=posix" + +JOB_COUNT=$(($(getconf _NPROCESSORS_ONLN) + 2)) show_help() { - cat <<HELP -usage: mingw-w64-build [OPTION]... ARCH... -Build the MinGW-w64 toolchain for ARCH(s) (i686 or x86_64). - - -h, --help display this help and exit - --version output version information and exit - --enable-pthreads enable pthreads via winpthreads - -Creates directories 'src' and 'bld' in the current directory and - removes them when complete. - -examples: - mingw-w64-build i686 - mingw-w64-build x86_64 - mingw-w64-build i686 x86_64 -HELP +cat <<EOF +Usage: + $0 [options] <arch>... + +Archs: + i686 Windows 32-bit + x86_64 Windows 64-bit + +Options: + -h, --help show help + -j <count>, --jobs <count> override make job count (default: $JOB_COUNT) + -p <path>, --prefix <path> install location (default: $ROOT_PATH/<arch>) + --keep-artifacts don't remove source and build files after a successful build + --disable-threads disable pthreads and STL <thread> + --cached-sources use existing sources instead of downloading new ones + --binutils-branch <branch> set Binutils branch (default: $BINUTILS_BRANCH) + --gcc-branch <branch> set GCC branch (default: $GCC_BRANCH) + --mingw-w64-branch <branch> set MinGW-w64 branch (default: $MINGW_W64_BRANCH) +EOF } -show_version() +error_exit() { - cat <<VERSION -mingw-w64-build $v_script -Copyright (C) 2020 Kyle Schwarz -License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. -VERSION + 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 } -error_exit() +arg_error() { - local error_text="$1" - shift + local error_msg="$1" + shift 1 - if [[ -z "$error_text" ]]; then - error_text="See 'build.log' for further details." - fi + error_exit "$error_msg, see --help for options" "$error_msg" +} - echo "mingw-w64-build: error: $error_text" >&3 +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" +} - exit 1 +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" } -clean_build() +change_dir() { - local build_dir="$1" + local path="$1" + shift 1 - rm -fr "$build_dir" - mkdir -p "$build_dir" - cd "$build_dir" || error_exit + execute "" "unable to cd to directory '$path'" \ + cd "$path" } download_sources() { - cd "$src" || error_exit - - echo "downloading mingw-w64" >&3 - git clone --depth 1 -b v8.x https://git.code.sf.net/p/mingw-w64/mingw-w64 mingw-w64-$v_mingww64 || error_exit - - echo "downloading binutils" >&3 - git clone --depth 1 -b binutils-2_35-branch git://sourceware.org/git/binutils-gdb.git binutils-$v_binutils || error_exit - - echo "downloading gcc" >&3 - git clone --depth 1 -b releases/gcc-10 git://gcc.gnu.org/git/gcc.git gcc-$v_gcc || error_exit - - local urls=( - "https://ftp.gnu.org/gnu/gmp/gmp-$v_gmp.tar.xz" - "https://ftp.gnu.org/gnu/mpfr/mpfr-$v_mpfr.tar.xz" - "https://ftp.gnu.org/gnu/mpc/mpc-$v_mpc.tar.gz" - "http://isl.gforge.inria.fr/isl-$v_isl.tar.xz" - ) - - for url in "${urls[@]}"; do - local archive="${url##*/}" - echo "downloading $archive" >&3 - curl -O "$url" || error_exit - echo "extracting $archive" >&3 - tar -xf "$archive" || error_exit - done - - cd "$src/gcc-$v_gcc" || error_exit - - ln -s "../gmp-$v_gmp" "gmp" - ln -s "../mpfr-$v_mpfr" "mpfr" - ln -s "../mpc-$v_mpc" "mpc" - ln -s "../isl-$v_isl" "isl" + remove_path "$SRC_PATH" + create_dir "$SRC_PATH" + change_dir "$SRC_PATH" + + execute "downloading MinGW-w64 source" "" \ + git clone --depth 1 -b "$MINGW_W64_BRANCH" \ + git://git.code.sf.net/p/mingw-w64/mingw-w64 mingw-w64 + + execute "downloading Binutils source" "" \ + git clone --depth 1 -b "$BINUTILS_BRANCH" \ + git://sourceware.org/git/binutils-gdb.git binutils + + execute "downloading GCC source" "" \ + git clone --depth 1 -b "$GCC_BRANCH" \ + git://gcc.gnu.org/git/gcc.git gcc + + execute "downloading config.guess" "" \ + curl -o config.guess \ + "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD" } -build_toolchain() +build() { - local host="$1-w64-mingw32" - local prefix="$wd/$host" - export PATH="$prefix/bin:$PATH" - - if [[ "$1" = "i686" ]]; then - i686_dwarf2="--disable-sjlj-exceptions --with-dwarf2" - fi - - if [[ "$pthreads" = true ]]; then - enable_threads="--enable-threads=posix" - fi - - rm -fr "$prefix" - - clean_build "$bld/binutils" - echo "configuring binutils" >&3 - "../../src/binutils-$v_binutils/configure" --prefix="$prefix" --disable-shared \ - --enable-static --with-sysroot="$prefix" --target="$host" \ - --disable-multilib --disable-nls --enable-lto --disable-werror || error_exit - echo "building binutils" >&3 - make -j $cpus || error_exit - echo "installing binutils" >&3 - make install || error_exit - - clean_build "$bld/mingw-w64" - echo "configuring mingw-w64-headers" >&3 - "../../src/mingw-w64-$v_mingww64/mingw-w64-headers/configure" --build="$build" \ - --host="$host" --prefix="$prefix/$host" || error_exit - echo "installing mingw-w64-headers" >&3 - make install || error_exit - cd "$prefix" || error_exit - ln -s "./$host" "./mingw" || error_exit - - clean_build "$bld/gcc" - echo "configuring gcc" >&3 - "../../src/gcc-$v_gcc/configure" --target="$host" --disable-shared \ - --enable-static --disable-multilib --prefix="$prefix" $i686_dwarf2 \ - --enable-languages=c,c++ --disable-nls $enable_threads || error_exit - echo "running 'make-gcc' for gcc" >&3 - make -j $cpus all-gcc || error_exit - echo "running 'install-gcc' for gcc" >&3 - make install-gcc || error_exit - - clean_build "$bld/mingw-w64" - echo "configuring mingw-w64-crt" >&3 - "../../src/mingw-w64-$v_mingww64/mingw-w64-crt/configure" --build="$build" --host="$host" \ - --prefix="$prefix/$host" --with-sysroot="$prefix/$host" || error_exit - echo "building mingw-w64-crt" >&3 - make -j $cpus || error_exit - echo "installing mingw-w64-crt" >&3 - make install || error_exit - - if [[ "$pthreads" = true ]]; then - clean_build "$bld/winpthreads" - echo "configuring winpthreads" >&3 - "../../src/mingw-w64-$v_mingww64/mingw-w64-libraries/winpthreads/configure" --build="$build" \ - --host="$host" --disable-shared --enable-static --prefix="$prefix/$host" || error_exit - echo "building winpthreads" >&3 - make -j $cpus || error_exit - echo "installing winpthreads" >&3 - make install || error_exit - fi - - cd "$bld/gcc" || error_exit - echo "building gcc" >&3 - make -j $cpus || error_exit - echo "installing gcc" >&3 - make install || error_exit - - return 0 + 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" = "i686" ]; then + local i686_dwarf2="--disable-sjlj-exceptions --with-dwarf2" + 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" + + 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 \ + $i686_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-sysroot="$prefix/$host" + + 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 - ;; - --version) - show_version - exit - ;; - --enable-pthreads) - pthreads=true - ;; - -?*) - echo "mingw-w64-build: error: unknown option: '$1'" >&2 - exit - ;; - *) - break - esac - - shift + 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="$2" + shift + else + arg_error "'--prefix' requires a non-empty option argument" + fi + ;; + --prefix=?*) + PREFIX=${1#*=} + ;; + --prefix=) + arg_error "'--prefix' requires a non-empty option argument" + ;; + --keep-artifacts) + KEEP_ARTIFACTS=1 + ;; + --disable-threads) + ENABLE_THREADS="" + ;; + --cached-sources) + CACHED_SOURCES=1 + ;; + --binutils-branch) + if [ "$2" ]; then + BINUTILS_BRANCH="$2" + shift + else + arg_error "'--binutils-branch' requires a non-empty option argument" + fi + ;; + --binutils-branch=?*) + BINUTILS_BRANCH=${1#*=} + ;; + --binutils-branch=) + arg_error "'--binutils-branch' requires a non-empty option argument" + ;; + --gcc-branch) + if [ "$2" ]; then + GCC_BRANCH="$2" + shift + else + arg_error "'--gcc-branch' requires a non-empty option argument" + fi + ;; + --gcc-branch=?*) + GCC_BRANCH=${1#*=} + ;; + --gcc-branch=) + arg_error "'--gcc-branch' requires a non-empty option argument" + ;; + --mingw-w64-branch) + if [ "$2" ]; then + MINGW_W64_BRANCH="$2" + shift + else + arg_error "'--mingw-w64-branch' requires a non-empty option argument" + fi + ;; + --mingw-w64-branch=?*) + MINGW_W64_BRANCH=${1#*=} + ;; + --mingw-w64-branch=) + arg_error "'--mingw-w64-branch' requires a non-empty option argument" + ;; + 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 -if [[ "$PWD" = *" "* ]]; then - echo "mingw-w64-build: error: working path contains spaces" >&2 - exit 1 +if [ ! "$BUILD_I686" ] && [ ! "$BUILD_X86_64" ]; then + arg_error "no ARCH was specified" fi -if [[ -z "$@" ]]; then - echo "mingw-w64-build: error: missing ARCH option" >&2 - echo "See 'mingw-w64-build --help' for build options." >&2 - exit 1 +MISSING_EXECS="" +for exec in g++ flex bison git makeinfo m4 bzip2 curl make diff; 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 -for arch in $@; do - if [[ "$arch" != "i686" ]] && [[ "$arch" != "x86_64" ]]; then - echo "mingw-w64-build: error: invalid ARCH: '$arch'" >&2 - exit 1 - fi -done +TOTAL_STEPS=0 -progs=( - "curl" - "gzip" - "bzip2" - "git" - "make" - "g++" - "tr" - "tar" - "svn" - "flex" - "bison" - "makeinfo" -) -missing_progs="" -for prog in "${progs[@]}"; do - if ! command -v $prog >/dev/null; then - missing_progs="$prog $missing_progs" - fi -done -if [[ -n "$missing_progs" ]]; then - echo "mingw-w64-build: missing required program(s): $missing_progs" >&2 - exit 1 +if [ "$CACHED_SOURCES" ]; then + if [ ! -f "$SRC_PATH/config.guess" ]; 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 -cpus=$(grep -c processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu | tr -d "\n" 2>/dev/null) -(( cpus += 2 )) -build=$(curl -s "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD" | sh) -wd="$PWD" -src="$wd/src" -bld="$wd/bld" -log="$wd/bld/build.log" +if [ "$BUILD_I686" ] && [ "$BUILD_X86_64" ]; then + THREADS_STEPS=$((THREADS_STEPS * 2)) + BUILD_STEPS=26 +else + BUILD_STEPS=13 +fi -rm -fr "$log" "$src" "$bld" -mkdir "$bld" "$src" -download_sources 3>&1 1>>"$log" 2>&1 +TOTAL_STEPS=$((TOTAL_STEPS + THREADS_STEPS + BUILD_STEPS)) -for arch in $@; do - build_toolchain "$arch" 3>&1 1>>"$log" 2>&1 -done -rm -fr "$bld" "$src" +if [ "$PREFIX" ]; then + I686_PREFIX="$PREFIX" + X86_64_PREFIX="$PREFIX" +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 +fi + +BUILD=$(sh "$SRC_PATH/config.guess") + +change_dir "$SRC_PATH/gcc" + +execute "" "failed to download GCC dependencies" \ + ./contrib/download_prerequisites + +COMPLETE_MSG="complete, to use MinGW-w64 everywhere add" + +if [ "$BUILD_I686" ]; then + build i686 "$I686_PREFIX" + COMPLETE_MSG="$COMPLETE_MSG '$I686_PREFIX/bin'" +fi + +if [ "$BUILD_X86_64" ]; then + build x86_64 "$X86_64_PREFIX" + if [ "$BUILD_I686" ]; then + COMPLETE_MSG="$COMPLETE_MSG and " + fi + COMPLETE_MSG="$COMPLETE_MSG '$X86_64_PREFIX/bin'" +fi + +COMPLETE_MSG="$COMPLETE_MSG to PATH." + +if [ ! "$KEEP_ARTIFACTS" ]; then + remove_path "$SRC_PATH" + remove_path "$BLD_PATH" + remove_path "$LOG_FILE" +fi + +printf "%s\n" "$COMPLETE_MSG" exit 0 |