There is a combined
tree method of
building GCC. You have to be careful that the checkouts of
binutils-gdb
, newlib-cygwin
, and gcc
are fairly similar or you
get errors due to API changes. And just checking out the latest stable
version of each isn't enough.
I hit an issue with latest stable versions of each project. ldirname
was changed from a private to a public function on 2025-03-18. It was
made this way for gcc 15.1. But the latest stable release of binutils,
which I had checked out, was 2.44, from February 2025. So it still had
ldirname
marked as static. And therefore the combined tree did not
compile.
The solution was to simply use the master branch of each project.
Here's the full workflow:
cd ~/repos
mkdir gnu
cd gnu
git clone https://gcc.gnu.org/git/gcc.git
git clone https://sourceware.org/git/newlib-cygwin.git
git clone https://sourceware.org/git/binutils-gdb.git
rm -rf src-combined/
mkdir src-combined
cd newlib-cygwin && find . -print | cpio -pdlm ../src-combined && cd ..
cd binutils-gdb && find . -print | cpio -pdlmu ../src-combined && cd ..
cd gcc && find . -print | cpio -pdlmu ../src-combined && cd ..
rm -rf build-combined-arm-none-eabi
mkdir build-combined-arm-none-eabi
cd build-combined-arm-none-eabi
../src-combined/configure --target=arm-none-eabi --disable-gdb --enable-languages=c,c++ --prefix=$HOME/.local/
make -j8
make install
Although there must be a libc at the end called libc_nano
, as that
is what is expected by STM32CubeMX. You might expect that if you
compile with a certain nano
flag, then it would generate libc_nano
rather than libc
. Nope. Even though the libc_nano
convention is
expected by some of the source code e.g. in *.specs
files, the
creation of libc_nano
is done by the library packager. It's done
with a simple find and replace in the Debian
package. Which
is also what was recommended on newlib
mailing list in this
message in
2018.
Ew. crosstool-ng does it with symlinks, which is a little better.
So the way to do it is use these configure flags (from this ARM forum post):
--disable-newlib-supplied-syscalls \
--enable-newlib-reent-check-verify \
--enable-newlib-reent-small \
--enable-newlib-retargetable-locking \
--disable-newlib-fvwrite-in-streamio \
--disable-newlib-fseek-optimization \
--disable-newlib-wide-orient \
--enable-newlib-nano-malloc \
--disable-newlib-unbuf-stream-opt \
--enable-lite-exit \
--enable-newlib-global-atexit \
--enable-newlib-nano-formatted-io \
--disable-nls
Then later symlink libc_nano
to libc
.
You might think an easier option is to use libnewlib-arm-none-eabi
from the package manager alongside the custom compiler. In fact, you
could use binutils-arm-none-eabi
too and not even have to do the
combined tree build method.
If that worked well, there would still be a problem: packages made
with autoconf
usually don't support the uninstall
target.
Normally that's no problem as the toolchain is installed using a package manager and can be uninstalled that way. But if you want to do a user-local install without touching any system dirs, you cannot use the system package manager. My judgement is that the best solution is GNU Stow. I tried it and it's actually quite slick, build just for this kind of thing.
People (and error messages) say, "Check config.log
for autoconf
errors". But you'll find that the top-level config.log
has no
helpful information. It's just information from your initial
configure
. So what's up? There is more than one config.log
. One
for each sub-invocation of configure
which happens after make -j8
.
There are messages in the error log that look like: Configuring in arm-none-eabi/libstdc++-v3
. Look in the directory indicated most
recently in this way for a file config.log
. This will have the
information you need to troubleshoot.
Having spent some time wrestling with GCC, I have come to the conclusion that
--without-headers
does a lot more than the name and description
suggests, disabling lots of autoconf tests which will not pass
for cross-compilers for bare-metal targets for a variety of
reasons, such as no syscall implementations.AS_FOR_TARGET
defaults not to
$(TARGET)-as
but rather as
. Which of course on the host
refers to the host assembler. Not the target assemler. Duh.So the conclusion here is: do not build your own toolchain if you can
at all help it. IT IS NOT WORTH IT. Just use
crosstool-ng. Probably there's a way to leverage GNU stow to get the
crosstool-ng tools into ~/.local/
.
And if you must, copy the flags from the Debian package.
Random note: libgcc
contains code for operations too complicated for the compiler
to emit itself, such as soft floating-point operations and integer
multiplication, on some platforms.
Please send comments to blogger-jack@pearson.onl.