musl-cross-make/scripts/winner
2024-01-10 03:39:51 +08:00

388 lines
13 KiB
Bash
Executable File

#!/bin/sh
#===============================================================
# Filename : scripts/winner
# Purpose : Builds Windows-to-Linux cross-compiler toolchains.
# Authors : Zach van Rijn <me@zv.io>
# License : MIT
# Revision : 20200303
#===============================================================
#---------------------------------------------------------------
# README
#
# overview
# --------
#
# This script builds "musl-cross-make" cross-compiler toolchains
# that are hosted on Windows and target Linux. For example, your
# Windows XP machine can use up-to-date versions of GCC to build
# code (C, C++, Fortran) for your MIPS router. The libc used is
# called 'musl': https://www.musl-libc.org/faq.html
#
# Others have tried and failed to deliver what you're able to do
# with this tiny script. Additions to this list are welcome:
#
# * https://gnutoolchains.com/download/
# * (um?)
#
# What does this look like? Modern GCC that does:
#
# * Win32 --> ARM, Motorola 68000, MIPS, OpenRISC, PowerPC,
# RISC-V, S/390, SuperH, x86-based, more?
#
# The goal, of course, is to achieve parity with musl.cc's Linux
# offerings. A link to pre-built Windows binaries is now public,
# and this is the script to reproduce them. https://win.musl.cc/
#
#
# build platforms
# ---------------
#
# In absolute theory, one can build this toolchain suite using a
# "native" toolchain from 'musl.cc' suitable for your platform,
# to build a MinGW-w64 cross-compiler (hosted on your platform,
# targeting i686- or x86_64- Windows), then use that toolchain
# to build the suite. Some may exist here: https://more.musl.cc/
#
# In practice, you just need 'i686-w64-mingw32-cross' for 32-bit
# or 'x86_64-w64-mingw32-cross' for 64-bit that runs on your own
# Linux (or Windows, with Cygwin or MSYS2) system.
#
#
# requirements
# ------------
#
# Consider running this script inside of an isolated environment
# such as a container or virtual machine. While not required, we
# do not recommend running any foreign scripts or binaries in an
# important environment. You'll need the following packages:
#
# * cmake
# * curl
# * git
# * make
# * patch (GNU)
# * rsync
# * tar
# * xz
# * zip
#
# e.g., apk add cmake curl git make patch rsync tar xz zip
#
# You'll also need an internet connection (or manually do so) to
# obtain corresponding "donor" toolchains from musl.cc; what we
# are doing is pulling musl and the Linux kernel headers from an
# existing toolchain, rather than fuss with getting them to play
# nicely with the "Canadian" cross infrastructure.
#
#
# other notes
# -----------
#
# * Toolchains cannot be built with kernel headers; these are
# copied into the output directory after the initial build.
# Kernel version is that of donor toolchain.
#
# * Toolchains cannot be built with the musl library; this is
# copied into the output directory after the initial build.
# musl version is that of donor toolchain, but may be flaky.
#
# * If you do not uncomment the 'nano' line, you will build a
# large number of toolchains. This requires an exceptional
# amount of disk space and time. This is what I use it for.
#
#
# to-do
# -----
#
# * Fix underlying issue causing kernel headers and musl to be
# not built or installed correctly.
#
# * Generate Cygwin (and/or MSYS2) packages for distribution.
#---------------------------------------------------------------
# Configuration.
## Component Versions
#
# These options are self explanatory, but *must* correspond to a
# supported version within the "musl-cross-make" repository. One
# other factor to consider is that kernel headers and musl libc
# will be harvested from a "donor" toolchain; these versions do
# not necessarily correspond to what is built here (yet, TODO).
#
GCC_VER=9.3.0
BINUTILS_VER=2.34
MUSL_VER=git-0a005f499cf39822166dd4db3d2d31f0639f1b1b
GMP_VER=6.2.0
MPC_VER=1.1.0
MPFR_VER=4.1.0
LINUX_VER=5.4.50 # TODO: proper install, no rsync
## Directories
#
# By default, all toolchains that can be built, are built. This
# requires a significant amount of disk space. Please ensure you
# have at least 50GB of free disk space in these directories:
#
base="/tmp/winner_src" # base source directory
huge="/tmp/winner_bld" # base build directory
logs="/tmp/winner_log" # suite build log directory
zips="/tmp/winner_bin" # completed toolchains go here
## Toolchain Mirror
#
# If you have access to an x86_64 Linux machine, or one that has
# an x86_64 QEMU user-mode emulator registered in 'binfmt_misc',
# you will always be using the latest available software.
#
musl=https://more.musl.cc # more.musl.cc or mirror
## Toolchain Naming Conventions
#
# The musl.cc toolchains follow a simple naming convention: all
# cross compilers are suffixed with '-cross', native '-native'.
# If you're using a different mirror or convention, set it here.
#
csuf=-cross # cross suffix
nsuf=-native # native suffix
## Toolchain Tuples
#
# Values can be found at 'https://more.musl.cc/' where the $user
# variable corresponds to your build platform, and $host to your
# intended Windows development environment. Note that unless the
# website says otherwise, only the 'i686-linux-musl' toolchain
# directory is up-to-date. If you can't find what you're looking
# for you must build a MinGW-w64 suitable toolchain from source.
#
user=i686-linux-musl # platform that builds suite
host=i686-w64-mingw32 # platform that runs suite
## Build Environment
#
# This variable is extended during the toolchain download step.
#
kale="${base}/${host}${csuf}/bin:${base}/${user}${csuf}/bin";
## Repositories
#
# The build infrastructure used is called "musl-cross-make" and
# is upstream https://github.com/richfelker/musl-cross-make, but
# this version is incompatible with the current script. It's out
# of date, too, so please leave the default unless you fork it.
#
name=musl-cross-make
repo=https://git.zv.io/toolchains/${name}
brch=master # branch name (no assumptions!)
## Suite Targets
#
# Now that RISC-V patches are (unofficially) merged into musl, a
# single text file with target tuples (which comprise the suite)
# may now be used. Modify this with e.g. a pastebin link if you
# wish to use a different list (this one is self-updating).
#
list=${repo}/raw/${brch}/scripts/triples.txt
filt=tuples.txt # filename of saved tuples list
## Suite Configuration
#
# To facilitate users' needs in customizing the toolchain suite,
# a configuration file is embedded below. These settings *must*
# be supported by the repository specified above.
#
# Note: items that are prefixed/suffixed with double underscores
# are automatically populated later. Do not modify them here!
#
conf=$(cat <<'EOF'
STAT = -static --static
FLAG = -g0 -O2 -fno-align-functions -fno-align-jumps -fno-align-loops -fno-align-labels
ifneq ($(NATIVE),)
COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}" FC="$(HOST)-gfortran ${STAT}"
else
COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}" FC="gfortran ${STAT}"
endif
COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" FFLAGS="${FLAG}" LDFLAGS="-s ${STAT}"
COMMON_CONFIG += --disable-nls --disable-bootstrap --build=__USER__ --host=__HOST__ --target=__TARG__
GCC_VER = __GCC_VER__
BINUTILS_VER = __BINUTILS_VER__
MUSL_VER = __MUSL_VER__
GMP_VER = __GMP_VER__
MPC_VER = __MPC_VER__
MPFR_VER = __MPFR_VER__
LINUX_VER = __LINUX_VER__
EOF
);
#---------------------------------------------------------------
# Subroutines.
# Download preliminary toolchains.
#
get_tool ()
{
mkdir -p "${base}";
# host
if [ ! -d "${base}/${host}${csuf}" ]; then
curl ${musl}/${user}/${host}${csuf}.tgz \
| tar 2>/dev/null -C "${base}" -xzf -;
(
cd "${base}/${host}${csuf}/bin";
find . -maxdepth 1 -type f | while read k; do
ln -sf ${k} ${k#*-*-*-};
done;
)
fi
# build
if [ ! -d "${base}/${user}${csuf}" ]; then
curl ${musl}/${user}/${user}${csuf}.tgz \
| tar 2>/dev/null -C "${base}" -xzf -;
fi
}
# Clone a suitable "musl-cross-make" repository.
#
get_repo ()
{
[ -d "${base}" ] || exit 1;
[ ! -d "${base}/${name}" ] || return;
git clone ${repo} "${base}/${name}";
}
# Overwrite any existing configuration (config.mak) template.
#
get_conf ()
{
[ -d "${base}/${name}" ] || exit 1;
printf > "${base}/${name}/config.mak" "%s\n" \
"${conf}";
}
# Fetch an up-to-date list of possible target tuples. Allow the
# user to edit this list, if the line is uncommented, before DL.
#
get_list ()
{
[ ! -f "${base}/${filt}" ] || return;
curl -o "${base}/${filt}" ${list};
sed -i "${base}/${filt}" -e '/mingw/d';
#nano "${base}/${filt}";
}
# Download all necessary target toolchains.
#
get_targ ()
{
# targets (if different from build)
cat "${base}/${filt}" | grep -v "#" | while read k; do
if [ ! -d "${base}/${k}${csuf}" ]; then
curl ${musl}/${user}/${k}${csuf}.tgz \
| tar 2>/dev/null -C "${base}" -xzf -;
fi
done;
}
# Build the compiler suite without musl or kernel headers. Note:
# the '-ik' in the 'make' command is required to avoid issues in
# areas that have not yet been investigated but don't affect the
# correctness of the resulting toolchain.
#
run_make ()
{
mkdir -p "${huge}";
mkdir -p "${logs}";
cat "${base}/${filt}" | grep -v "#" | while read k; do
get_conf; sed -i "${base}/${name}/config.mak" \
-e "s@__USER__@${user}@" \
-e "s@__HOST__@${host}@" \
-e "s@__TARG__@${k}@" \
\
-e "s@__GCC_VER__@${GCC_VER}@" \
-e "s@__BINUTILS_VER__@${BINUTILS_VER}@" \
-e "s@__MUSL_VER__@${MUSL_VER}@" \
-e "s@__GMP_VER__@${GMP_VER}@" \
-e "s@__MPC_VER__@${MPC_VER}@" \
-e "s@__MPFR_VER__@${MPFR_VER}@" \
-e "s@__LINUX_VER__@@";
if [ ! -d "${huge}/${k}${csuf}" ]; then
PATH="${kale}:${base}/${k}${csuf}/bin:${PATH}" \
\
CC="${host}-gcc" \
CXX="${host}-g++" \
RANLIB="${host}-ranlib" \
\
CC_FOR_BUILD="${user}-gcc" \
CXX_FOR_BUILD="${user}-g++" \
RANLIB_FOR_BUILD="${user}-ranlib" \
\
CC_FOR_TARGET="${k}-gcc" \
CXX_FOR_TARGET="${k}-g++" \
RANLIB_FOR_TARGET="${k}-ranlib" \
\
make -ik -C "${base}/${name}" -O install \
TARGET=${k} OUTPUT="${huge}/${k}${csuf}" \
2>&1 | tee "${logs}/${k}${csuf}.log";
fi
done;
}
# Synchronize a donor toolchain's libraries and headers (for the
# sole purposes of musl and kernel headers) with the newly-built
# Windows-hosted toolchain.
#
run_sync ()
{
cat "${base}/${filt}" | grep -v "#" | while read k; do
sync=$(cat <<EOF
${k}${csuf}/${k}/include/
${k}${csuf}/${k}/lib/
EOF
);
for n in ${sync}; do rsync -raz --ignore-existing \
"${base}/${n}" "${huge}/${n}";
done;
done;
}
# Windows does not appreciate symbolic links. Delete them. Then
# pack the toolchains into zip files. They're ready for distro.
#
run_pack ()
{
mkdir -p "${zips}";
cat "${base}/${filt}" | grep -v "#" | while read k; do
if [ ! -e "${zips}/${k}${csuf}.zip" ]; then
(
cd "${huge}";
find ${k}${csuf} -type l -delete;
zip -rq "${zips}/${k}${csuf}.zip" ${k}${csuf};
)
fi
done
}
#---------------------------------------------------------------
# Driver.
get_tool; # Download initial toolchains.
get_repo; # Clone "musl-cross-make" repo.
get_conf; # Write toolchain configuration.
get_list; # Generate list of targets.
get_targ; # Fetch "donor" toolchains.
run_make; # Build specified toolchains.
run_sync; # Harvest/inject "donor" organs.
run_pack; # Pack output for distribution.