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

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.