Last active
January 18, 2024 05:58
-
-
Save firasuke/82ee9ed032aaf61af26826e07a3db14d to your computer and use it in GitHub Desktop.
Building an x86-64 cross compiler targeting musl libc (musl-cross-make style)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/dash -e | |
# Copyright (c) 2020, Firas Khalil Khana | |
# Distributed under the terms of the ISC License | |
# | |
# Credits to Rich Felker and musl-cross-make for making this possible | |
# | |
set -e | |
umask 022 | |
# | |
# Colors | |
# | |
BLUEC='\033[1;34m' | |
REDC='\033[1;31m' | |
GREENC='\033[1;32m' | |
NORMALC='\033[0m' | |
# | |
# Package Versions | |
# | |
binutils_ver=2.34 | |
gcc_ver=10.1.0 | |
gmp_ver=6.2.0 | |
isl_ver=0.22.1 | |
mpc_ver=1.1.0 | |
mpfr_ver=4.0.2 | |
musl_ver=1.2.0 | |
# | |
# Package URLs (The usage of ftpmirror for GNU packages is preferred.) | |
# | |
binutils_url=https://ftpmirror.gnu.org/binutils/binutils-$binutils_ver.tar.lz | |
gcc_url=https://ftpmirror.gnu.org/gcc/gcc-$gcc_ver/gcc-$gcc_ver.tar.xz | |
gmp_url=https://ftpmirror.gnu.org/gmp/gmp-$gmp_ver.tar.lz | |
isl_url=http://isl.gforge.inria.fr/isl-$isl_ver.tar.xz | |
mpc_url=https://ftpmirror.gnu.org/mpc/mpc-$mpc_ver.tar.gz | |
mpfr_url=https://www.mpfr.org/mpfr-current/mpfr-$mpfr_ver.tar.xz | |
musl_url=https://www.musl-libc.org/releases/musl-$musl_ver.tar.gz | |
# | |
# Package Checksums (sha512sum) | |
# | |
binutils_sum=f4aadea1afa85d9ceb7be377afab9270a42ab0fd1fae86a7c69510b80de1aaac76f15cfb8730f9d233466a89fd020ab7e6e705e754c6b40f5fe2d16a5214562e | |
gcc_sum=0cb2a74c793face751f42bc580960b00e2bfea785872a0a2155f1f1dbfaa248f9591b67f4322db0f096f8844aca9243bc02732bda106c3b6e43b02bb67eb3096 | |
gmp_sum=9975e8766e62a1d48c0b6d7bbdd2fccb5b22243819102ca6c8d91f0edd2d3a1cef21c526d647c2159bb29dd2a7dcbd0d621391b2e4b48662cf63a8e6749561cd | |
isl_sum=8dc7b0c14e5bfdca8f2161be51d3c9afcd18bc217bb19b7de01dbba0c6f3fdc2b725fb999f8562c77bf2918d3005c9247f7a58474a6da7697390067944d4d4aa | |
mpc_sum=72d657958b07c7812dc9c7cbae093118ce0e454c68a585bfb0e2fa559f1bf7c5f49b93906f580ab3f1073e5b595d23c6494d4d76b765d16dde857a18dd239628 | |
mpfr_sum=d583555d08863bf36c89b289ae26bae353d9a31f08ee3894520992d2c26e5683c4c9c193d7ad139632f71c0a476d85ea76182702a98bf08dde7b6f65a54f8b88 | |
musl_sum=58bd88189a6002356728cea1c6f6605a893fe54f7687595879add4eab283c8692c3b031eb9457ad00d1edd082cfe62fcc0eb5eb1d3bf4f1d749c0efa2a95fec1 | |
# | |
# Development Directories | |
# | |
CURDIR="$PWD" | |
SRCDIR="$CURDIR/sources" | |
BLDDIR="$CURDIR/builds" | |
PCHDIR="$CURDIR/patches" | |
[ ! -d $SRCDIR ] && echo "${BLUEC}=>${NORMALC} Creating the sources directory...\n" && mkdir $SRCDIR | |
[ ! -d $BLDDIR ] && echo "${BLUEC}=>${NORMALC} Creating the builds directory...\n" && mkdir $BLDDIR | |
[ ! -d $PCHDIR ] && echo "${BLUEC}=>${NORMALC} Creating the patches directory...\n" && mkdir $PCHDIR | |
# | |
# Preparation Function - gtpackage() | |
# | |
gtpackage() { | |
cd $SRCDIR | |
if [ ! -d $1 ]; then | |
mkdir $1 | |
else | |
echo "${REDC}=>${NORMALC} $1 source directory already exists, skipping..." | |
fi | |
cd $1 | |
HOLDER="$(basename $2)" | |
if [ ! -f "$HOLDER" ]; then | |
echo "${GREENC}=>${NORMALC} Fetching "$HOLDER"..." | |
wget "$2" | |
else | |
echo "${REDC}=>${NORMALC} "$HOLDER" already exists, skipping..." | |
fi | |
echo "${GREENC}=>${NORMALC} Verifying "$HOLDER"..." | |
echo "$3 $HOLDER" | sha512sum -c || { | |
echo "${REDC}=>${NORMALC} "$HOLDER" is corrupted, redownloading..." && | |
rm "$HOLDER" && | |
wget "$2"; | |
} | |
rm -fr $1-$4 | |
echo "${GREENC}=>${NORMALC} Unpacking $HOLDER..." | |
tar xf $HOLDER -C . | |
echo | |
} | |
gtpackage binutils "$binutils_url" $binutils_sum $binutils_ver | |
gtpackage gcc "$gcc_url" $gcc_sum $gcc_ver | |
gtpackage gmp "$gmp_url" $gmp_sum $gmp_ver | |
gtpackage isl "$isl_url" $isl_sum $isl_ver | |
gtpackage mpc "$mpc_url" $mpc_sum $mpc_ver | |
gtpackage mpfr "$mpfr_url" $mpfr_sum $mpfr_ver | |
gtpackage musl "$musl_url" $musl_sum $musl_ver | |
# | |
# Patching | |
# | |
# | |
# The gcc patch is for a bug that forces CET when cross compiling in both lto-plugin | |
# and libiberty. | |
# | |
cd $PCHDIR | |
[ ! -d gcc ] && mkdir gcc | |
cd gcc | |
if [ ! -f Enable-CET-in-cross-compiler-if-possible.patch ]; then | |
echo "${GREENC}=>${NORMALC} Fetching gcc Enable-CET-in-cross-compiler-if-possible.patch from upstream..." | |
wget https://raw.githubusercontent.com/glaucuslinux/glaucus/master/cerata/gcc/patches/upstream/Enable-CET-in-cross-compiler-if-possible.patch | |
else | |
echo "${REDC}=>${NORMALC} Enable-CET-in-cross-compiler-if-possible.patch already exists, skipping..." | |
fi | |
echo "${BLUEC}=>${NORMALC} Applying gcc Enable-CET-in-cross-compiler-if-possible.patch from upstream..." | |
cd $SRCDIR/gcc/gcc-$gcc_ver | |
patch -p1 -i $PCHDIR/gcc/Enable-CET-in-cross-compiler-if-possible.patch | |
echo | |
cd $CURDIR | |
# | |
# Don't change anything from here on, unless you know what you're doing. | |
# | |
if [ -d "$CURDIR/builds" ]; then | |
echo "${GREENC}=>${NORMALC} Cleaning builds directory..." | |
rm -fr "$CURDIR/builds" | |
mkdir "$CURDIR/builds" | |
fi | |
if [ -d "$CURDIR/toolchain" ]; then | |
echo "${GREENC}=>${NORMALC} Cleaning toolchain directory..." | |
rm -fr "$CURDIR/toolchain" | |
mkdir "$CURDIR/toolchain" | |
fi | |
if [ -d "$CURDIR/bsysroot" ]; then | |
echo "${GREENC}=>${NORMALC} Cleaning bsysroot directory..." | |
rm -fr "$CURDIR/bsysroot" | |
fi | |
# | |
# We fetch the latest upstream config.guess to correctly determine the value of | |
# BUILD (`--build`). | |
# | |
if [ ! -f $CURDIR/config.guess ]; then | |
echo "${GREENC}=>${NORMALC} Fetching the latest config.guess from upstream..." | |
wget "https://raw.githubusercontent.com/glaucuslinux/glaucus/master/cerata/binutils/config.guess" | |
chmod +x config.guess | |
else | |
echo "${REDC}=>${NORMALC} Latest config.guess already exists, skipping..." | |
fi | |
echo "=> Determining --build..." | |
XBUILD="$($CURDIR/config.guess)" | |
echo "=> --build set to $XBUILD" | |
echo | |
# | |
# Since this is a cross compiler, we want `--host` to be equal to `--build`. | |
# Native toolchains are outside the scope of this script. | |
# | |
echo "=> Setting --host equal to --build since we're cross compiling..." | |
XHOST=$XBUILD | |
# | |
# Available Target Architectures | |
# | |
XTARGET=x86_64-linux-musl | |
# | |
# Build Directories (GTSYSROOT can be empty?) | |
# | |
GTBSYSROOT="$CURDIR/bsysroot" | |
GTSYSROOT="/$XTARGET" | |
GTOUTPUT="$CURDIR/output" | |
# | |
# Make command | |
# | |
MAKE="make MULTILIB_OSDIRNAMES= INFO_DEPS= infodir= ac_cv_prog_lex_root=lex.yy MAKEINFO=true" | |
# | |
# FLAGS | |
# | |
CFLAGS="-O2" | |
CXXFLAGS="-O2" | |
# | |
# Uncomment these for a lighter toolchain. | |
# | |
#CFLAGS="-g0 -Os" | |
#CXXFLAGS="-g0 -Os" | |
#LDFLAGS="-s" | |
# | |
# Step 1: Configuring binutils | |
# | |
echo "=> Preparing binutils..." | |
cd $BLDDIR | |
mkdir binutils && cd binutils | |
# | |
# Notice how `--build` and `--host` are equal because we're "purely" cross | |
# compiling to `--target`. | |
# | |
# Note the use of an empty `--prefix`, and later the use of `DESTDIR` for | |
# installation. | |
# | |
echo "=> Configuring binutils..." | |
$SRCDIR/binutils/binutils-$binutils_ver/configure \ | |
--build=$XBUILD \ | |
--host=$XBUILD \ | |
--target=$XTARGET \ | |
--prefix= \ | |
--libdir=/lib \ | |
--with-sysroot=$GTSYSROOT \ | |
--disable-multilib \ | |
--disable-separate-code \ | |
--disable-werror \ | |
--enable-deterministic-archives | |
echo | |
# | |
# Step 2: Building binutils | |
# | |
echo "=> Building binutils..." | |
$MAKE \ | |
all | |
echo | |
# | |
# Step 3: GCC Prerequisites | |
# | |
# We track them manually instead of using `contrib/download_prerequisites` in | |
# gcc's sources. | |
# | |
echo "=> Preparing GCC prerequisites..." | |
cp -ar $SRCDIR/gmp/gmp-$gmp_ver $SRCDIR/gcc/gcc-$gcc_ver/gmp | |
cp -ar $SRCDIR/mpfr/mpfr-$mpfr_ver $SRCDIR/gcc/gcc-$gcc_ver/mpfr | |
cp -ar $SRCDIR/mpc/mpc-$mpc_ver $SRCDIR/gcc/gcc-$gcc_ver/mpc | |
cp -ar $SRCDIR/isl/isl-$isl_ver $SRCDIR/gcc/gcc-$gcc_ver/isl | |
echo | |
# | |
# Step 4: Configuring gcc | |
# | |
echo "=> Preparing gcc..." | |
cd $BLDDIR | |
mkdir gcc && cd gcc | |
# | |
# Again, everything said in binutils applies here. | |
# | |
# We need c++ language support to be able to build GCC, since GCC has big parts | |
# of its source code written in C++. | |
# | |
echo "=> Configuring gcc..." | |
AR_FOR_TARGET=$BLDDIR/binutils/binutils/ar \ | |
AS_FOR_TARGET=$BLDDIR/binutils/gas/as-new \ | |
LD_FOR_TARGET=$BLDDIR/binutils/ld/ld-new \ | |
NM_FOR_TARGET=$BLDDIR/binutils/binutils/nm-new \ | |
OBJCOPY_FOR_TARGET=$BLDDIR/binutils/binutils/objcopy \ | |
OBJDUMP_FOR_TARGET=$BLDDIR/binutils/binutils/objdump \ | |
RANLIB_FOR_TARGET=$BLDDIR/binutils/binutils/ranlib \ | |
READELF_FOR_TARGET=$BLDDIR/binutils/binutils/readelf \ | |
STRIP_FOR_TARGET=$BLDDIR/binutils/binutils/strip-new \ | |
$SRCDIR/gcc/gcc-$gcc_ver/configure \ | |
--build=$XBUILD \ | |
--host=$XBUILD \ | |
--target=$XTARGET \ | |
--prefix= \ | |
--libdir=/lib \ | |
--with-build-sysroot=$GTBSYSROOT \ | |
--with-sysroot=$GTSYSROOT \ | |
--enable-languages=c,c++ \ | |
--disable-bootstrap \ | |
--disable-assembly \ | |
--disable-werror \ | |
--disable-multilib \ | |
--enable-tls \ | |
--disable-libsanitizer \ | |
--disable-gnu-indirect-function \ | |
--enable-libstdcxx-time=rt | |
echo | |
# | |
# Step 5: Preparing the build sysroot $GTBSYSROOT | |
# | |
echo "=> Preparing the build sysroot..." | |
mkdir $GTBSYSROOT | |
# | |
# This symlink is basically a hack but it's needed... | |
# | |
# You can get rid of the symlink ($GTBSYSROOT/usr -> .) by: | |
# | |
# 1- Modifying the native include dir for gcc, by passing | |
# `--with-native-system-header-dir=/include` (firasuke) | |
# | |
# 2- Modifying `lib64` to `../../lib` and not `../lib` in the `t-linux64` file | |
# since $XTARGET/bin/ld is called before bin/$XTARGET-ld (firasuke) | |
# | |
ln -fnsv . $GTBSYSROOT/usr | |
# | |
# This symlink (lib32 -> lib) shouldn't be needed (ideally we prefer that lib | |
# stands for what was previously called lib64, and lib32 stands for lib32), but | |
# mcm does it, so we do it... | |
# | |
ln -fnsv lib $GTBSYSROOT/lib32 | |
# | |
# This is needed for some 64-bit Glibc hosts that might create a lib64 directory | |
# and install some GCC stuff there like libcc1 (firasuke) | |
# | |
ln -fnsv lib $GTBSYSROOT/lib64 | |
mkdir -p $GTBSYSROOT/include | |
echo | |
# | |
# Step 6: Building gcc | |
# | |
echo "=> Building gcc..." | |
cd $BLDDIR/gcc | |
$MAKE \ | |
all-gcc | |
echo | |
# | |
# Step 7: Configuring musl | |
# | |
echo "=> Preparing musl..." | |
cd $BLDDIR | |
mkdir musl && cd musl | |
# | |
# Again, empty prefix for musl. Also notice how `--host` here is set equal to | |
# `--target` (this is the de facto here, and you'd get the same results with | |
# `--target`. | |
# | |
echo "=> Configuring musl..." | |
CC="../gcc/gcc/xgcc -B ../gcc/gcc" \ | |
LIBCC="../gcc/$XTARGET/libgcc/libgcc.a" \ | |
$SRCDIR/musl/musl-$musl_ver/configure \ | |
--host=$XTARGET \ | |
--prefix= | |
echo | |
# | |
# Step 8: Installing musl headers to GTBSYSROOT | |
# | |
# With musl installs, you almost always should use a DESTDIR (that also should | |
# 99% be equal to gcc's and binutils `--with-sysroot` value, unless you know | |
# what you're doing... | |
# | |
echo "=> Installing musl-headers..." | |
$MAKE \ | |
DESTDIR=$GTBSYSROOT \ | |
install-headers | |
echo | |
# | |
# Step 9: Building gcc (libgcc) | |
# | |
cd $BLDDIR/gcc | |
$MAKE \ | |
enable_shared=no \ | |
all-target-libgcc | |
echo | |
# | |
# Step 10: Building musl | |
# | |
echo "=> Building musl..." | |
cd $BLDDIR/musl | |
$MAKE \ | |
AR=$BLDDIR/binutils/binutils/ar \ | |
RANLIB=$BLDDIR/binutils/binutils/ranlib | |
echo | |
# | |
# Step 11: Installing musl to GTBSYSROOT | |
# | |
echo "=> Installing musl to $GTBSYSROOT..." | |
$MAKE \ | |
AR=$BLDDIR/binutils/binutils/ar \ | |
RANLIB=$BLDDIR/binutils/binutils/ranlib \ | |
DESTDIR=$GTBSYSROOT \ | |
install | |
echo | |
# | |
# Step 12: Building gcc final | |
# | |
echo "=> Building gcc final..." | |
cd $BLDDIR/gcc | |
$MAKE | |
echo | |
# | |
# Step 13: Installing musl to GTSYSROOT | |
# | |
echo "=> Installing musl to GTSYSROOT..." | |
cd $BLDDIR/musl | |
$MAKE \ | |
AR=$BLDDIR/binutils/binutils/ar \ | |
RANLIB=$BLDDIR/binutils/binutils/ranlib \ | |
DESTDIR=$GTOUTPUT/$GTSYSROOT \ | |
install | |
echo | |
# | |
# Step 14: Installing gcc | |
# | |
echo "=> Installing gcc..." | |
cd $BLDDIR/gcc | |
$MAKE \ | |
DESTDIR=$GTOUTPUT \ | |
install | |
# | |
# Because many programs expect `cc`/`$XTARGET-cc` as their C compiler instead of | |
# explicitly specifying gcc. | |
# | |
ln -fnsv $XTARGET-gcc $GTOUTPUT/bin/$XTARGET-cc | |
# | |
# Step 15: Installing binutils | |
# | |
echo "=> Installing binutils..." | |
cd $BLDDIR/binutils | |
$MAKE \ | |
DESTDIR=$GTOUTPUT \ | |
install | |
echo "=> Done! Have fun!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script is broken, but I'm leaving it here for reference. Maybe I'll fix it when I have enough time, but who knows...
I recommend that you use mussel instead.