-
8. [Optional Quadruple-precision Support] Step 8:
cross-gcc
(libquadmath
) -
9. [Optional Fortran Support] Step 9:
cross-gcc
(libgfortran
)
The usage of ftpmirror for GNU packages is preferred.
We also try to use the smallest tarballs available from upstream (in order of preference):
- zst
- lz
- xz
- bzip2
- gz
Please don't change $MSYSROOT
to $CURDIR/toolchain/$XTARGET
like CLFS and
other implementations do because it'll break here (even if binutils
insists on
installing stuff to that directory).
All architectures require a static libgcc (aka libgcc-static
) to be built
before musl
.
libgcc-static
won't be linked against any C library, and will suffice to to
build musl
for these architectures.
All listed archs were tested and are fully working!
- aarch64
- armv4t
- armv5te
- armv6
- armv6kz (Raspberry Pi 1 Models A, B, B+, the Compute Module, and the Raspberry Pi Zero)
- armv7
- i486
- i586
- i686
- m68k
- microblaze
- microblazeel
- mips64
- mips64el
- mipsisa64r6
- mipsisa64r6el
- or1k
- powerpc
- powerpcle
- powerpc64
- powerpc64le
- riscv64
- s390x
- sh2
- sh2be
- sh2-fdpic
- sh2be-fdpic
- sh4
- sh4be
- x86-64
We start by using the tools available on the host system. We then switch to ours when they're available.
The --parallel
flag will use all available cores on the host system (3 * nproc
is being used instead of the traditional 2 * nproc + 1
, since it
ensures parallelism).
It's also common to see --enable-secureplt
added to cross-gcc
arguments
when the target is powerpc*
, but that's only the case to get musl
to support
32-bit powerpc
(as instructed by musl
's wiki, along with
--with-long-double-64
, which was replaced by --without-long-double-128
in
recent gcc
versions). For 64-bit powerpc
like powerpc64
and powerpc64le
,
there's no need to explicitly specify it (This needs more investigation, but it
works fine without it).
XARCH
is the arch that we are supporting and the user chooses
LARCH
is the arch that is supported by the linux
kernel (found in
$SRCDIR/linux/linux-$linux_ver/arch/
)
MARCH
is the arch that is supported by musl
(found in
$SRCDIR/musl/musl-$musl_ver/arch/
)
XTARGET
is the final target triplet
There's no such option as --with-float=hard
for this arch.
--enable-decimal-float
is the default on z9-ec and higher (e.g. z196).
The flags being used with make
ensure that no documentation is being built,
and it prevents binutils
from requiring texinfo
(binutils
looks for
makeinfo
, and it fails if it doesn't find it, and the build stops).
Also please don't use MAKEINFO=false
(which is what musl-cross-make
does),
because binutils
will still fail.
This is important as debugging will be easier knowing what the environmental variables are, and instead of assuming, the system can tell us by printing each of them to the log file.
Currently only gcc
is being patched to provide pure 64-bit support for 64-bit
architectures (this means that /lib/
will be used instead of /lib64/
, and
/lib32/
will be used instead of /lib/
).
We only want the headers to configure gcc
... Also with musl
installs, you
almost always should use a DESTDIR
(this should be the equivalent of setting
--with-sysroot
when configuring gcc
and binutils
.
We also need to pass ARCH=$MARCH
and prefix=/usr
since we haven't
configured musl
yet, to get the right versions of musl
headers for the
target architecture.
Unlike musl
, --prefix
for GNU stuff means where we expect them to be
installed, so specifying it will save you the need to add a DESTDIR
when
installing cross-binutils
.
The --target
specifies that we're cross compiling, and binutils
tools will
be prefixed by the value provided to it. There's no need to specify --build
and --host
as config.guess
and config.sub
are now smart enough to figure
them in ALMOST all GNU packages (yup, I'm looking at you gcc
...).
The use of --disable-werror
is a necessity now, as the build will fail
without it, or it may throw implicit-fallthrough warnings, among others
(thanks to Aurelian).
Notice how we specify a --with-sysroot
here to tell binutils
to consider
the passed value as the root directory of our target system in which it'll
search for target headers and libraries.
We manually track GCC's prerequisites instead of relying on
contrib/download_prerequisites
in gcc
's source tree.
Again, what's mentioned in cross-binutils
applies here.
C++ language support is needed to successfully build gcc
, since gcc
has
big chunks of its source code written in C++.
LTO is not a default language, but is built by default because --enable-lto
is enabled by default.
If you want to use zstd
as a backend for LTO, just add --with-zstd
below
and make sure you have zstd
(or zstd-devel
or whatever it's called)
installed on your host.
Notice how we're not optimizing libgcc-static
by passing -O0
to both the
CFLAGS
and CXXFLAGS
as we're only using libgcc-static
to build musl
,
then we rebuild it later on as a full libgcc-shared
.
We need a separate build directory for musl
now that we have our cross-gcc
ready. Using the same directory as musl
headers without reconfiguring musl
would break the ABI.
musl
can be configured with a nonexistent libgcc-static
(which is what
musl-cross-make
does), but we're able to build libgcc.a
before musl
so
it's considered existent here. (We can configure musl
with a nonexistent
libgcc.a
then go back to $BLDDIR/cross-gcc
and build libgcc.a
, then come
back to $BLDDIR/musl
and build musl
(which again is what musl-cross-make
does), but that's a lot of jumping, and we end up rebuilding libgcc
later on
as a shared version to be able to compile the rest of gcc
libs, so why confuse
ourselves...).
We can specify install-libs install-tools
instead of install
(since we
already have the headers installed (with install-headers above
)), but
apparently the install
target automatically skips the headers if it found them
already installed.
Almost all implementations of musl
based toolchains change the symlink
between LDSO and the libc.so because it'll be wrong almost always...
After building musl
, we need to rebuild libgcc
but this time as
libgcc-shared
to be able to build the following gcc
libs (libstdc++-v3
and
libgomp
which would complain about a missing -lgcc_s
and would error out
with C compiler doesn't work
...).
We need to run make distclean
and not just make clean
to make sure the
leftovers from the building of libgcc-static
are gone so we can build
libgcc-shared
without having to restart the entire build just to build
libgcc-shared
!
We specify enable_shared=yes
here which may not be needed but is highly
recommended to ensure that this step results in a shared version of libgcc
.
It's a good idea to leave the support for C++ enabled as many programs require
it (e.g. gcc
).
If you're planning on targeting a machine with two or more cores, then it might
be a good idea to enable support for OpenMP optimizations as well (beware as
some packages may fail to build with OpenMP enabled e.g. grub
).
If you're building a toolchain with Fortran support (or otherwise need or want support for quadruple-precision floating point arithmetic), you will want to enable support for libquadmath. This is enabled when building for Fortran by default.
If you're building Fortran support, mussel
will build gcc's implementation of
Fortran's standard library.
If you're planning on targeting a Linux system then it's a good idea to include support for Linux kernel headers as several packages require them.
We first perform a mrproper
to ensure that our kernel source tree is clean.
We won't be polluting our kernel source tree which is why we're specifying
O=$BLDDIR/linux
(which I believe may or may not be used since we're
only installing the kernel header files and not actually building anything, but
just to be safe...).
The headers_install
target requires rsync
to be available (this is the
default as of 5.3
, it also performs additional cleaning on *.cmd
files which
may require manual cleaning if we're manually copying the headers (in the case
of rsync
not being available, which isn't recommended)).
As of gcc
10, the flag -fno-common
is now enabled by default, which in
most cases is a good thing because it helps in performance but for pkgconf
it
will result in breakage which is why we're passing -fcommon
instead.
Since we're building our own pkgconf
it should be able to run on where the
toolchain will be hosted, and it will be built on the same machine that we used
to build our toolchain, this makes --build
equal to --host
equal to the
machine we're building everything on. There's no need to set --target
because
pkgconf
doesn't produce binaries or executables that can be run on a given
target, hence the option is irrelevant here. You might also notice that since
--build
is equal to --host
(which is mostly x86_64-pc-linux-gnu
) then why
aren't we using the host's pkg-config
or pkgconf
in the first place (since
both ours and the host's will be compiled using the same toolchain installed on
the host system), and we already answered that in the README.md
file (we can
make use of the host's pkg-config
or pkgconf
by setting 3-5 environment
variables that point to where we're storing our relevant .pc
files). The only
advantage we have when building our own pkg-config
or pkgconf
is that we can
configure these options at compile time instead of relying on environment
variables, and that's pretty much about it...
It's also a good idea to symlink pkg-config
to pkgconf
.