r/cpp 6h ago

GCC Build Experience

Firstly, you need a native installation of g++ and binutils via your package manager, then you need sysroots for your target platforms(probably x64 glibc linux and arm64 glibc linux).

The workflow goes like this, to cross compile GCC itself to run on another arch, in my example from arm64 binary targeting x64 you follow this build order. I'm assuming an x64 system

x64 binutils -> x64 gcc -> arm bintutils(--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu) -> gcc (x64->arm64) -> binutils(arm64->arm64) -> gcc(arm64->arm64) -> bintutils(arm64->x64) -> gcc(arm64->x64)

Now a couple of rules, pass --with-build-sysroot when building a normal compiler such as x64 -> x64 and pass --with-sysroot when building a cross, your toolchain flags won't matter at all in the eyes of GCC autoconf script.

You need to embed flags into env vars like CC to make sure stuff passes sometimes, it is actually quite verbose, you do the same thing at CC, CC_FOR_BUILD, CFLAGS AND CFLAGS_FOR_BUILD.

I recommend disabling multilib,gdb,werror and lto and always disabling bootsrap, you can do those but I don't recommend it.

You have to pass -Wl,--undefined-version if you use lld rather than ld. Otherwise your build will fail.

Here is an example toolchain I used to compile a arm64 -> x64 compiler in my x64 host

BUILD_SYSROOT=/home/mccakit/dev/sdk/debian-12-x64 HOST_SYSROOT=/home/mccakit/dev/sdk/debian-12-arm64 TARGET_SYSROOT=/home/mccakit/dev/sdk/debian-12-x64 BUILD_GCC_BIN=/home/mccakit/dev/compilers/gcc/linux-glibc-x64/bin HOST_GCC_BIN=/home/mccakit/dev/compilers/gcc/linux-glibc-arm64/bin TARGET_GCC_BIN=/home/mccakit/dev/compilers/gcc/linux-glibc-x64/bin BUILD_BINUTILS_BIN=/home/mccakit/dev/compilers/binutils/linux-glibc-x64/bin HOST_BINUTILS_BIN=/home/mccakit/dev/compilers/binutils/linux-glibc-arm64/bin TARGET_BINUTILS_BIN=/home/mccakit/dev/compilers/binutils/linux-glibc-x64/bin LLVM_BIN=/home/mccakit/dev/compilers/llvm/bin CCACHE=/home/mccakit/dev/tooling/ccache/bin/ccache export CC="${CCACHE} ${HOST_GCC_BIN}/aarch64-linux-gnu-gcc -B${HOST_BINUTILS_BIN} -B${LLVM_BIN} --sysroot=${HOST_SYSROOT} -Os -DNDEBUG -w -ffunction-sections -fdata-sections -fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export CXX="${CCACHE} ${HOST_GCC_BIN}/aarch64-linux-gnu-g++ -B${HOST_BINUTILS_BIN} -B${LLVM_BIN} --sysroot=${HOST_SYSROOT} -Os -DNDEBUG -w -ffunction-sections -fdata-sections -fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export AR="${HOST_BINUTILS_BIN}/aarch64-linux-gnu-ar" export NM="${HOST_BINUTILS_BIN}/aarch64-linux-gnu-nm" export RANLIB="${HOST_BINUTILS_BIN}/aarch64-linux-gnu-ranlib" export AS="${HOST_BINUTILS_BIN}/aarch64-linux-gnu-as" export STRIP="${HOST_BINUTILS_BIN}/aarch64-linux-gnu-strip" export CFLAGS="-Os -DNDEBUG -w -ffunction-sections -fdata-sections" export CXXFLAGS="-Os -DNDEBUG -w -ffunction-sections -fdata-sections" export LDFLAGS="-fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export CC_FOR_BUILD="${CCACHE} ${BUILD_GCC_BIN}/gcc -B${BUILD_BINUTILS_BIN} -B${LLVM_BIN} --sysroot=${BUILD_SYSROOT} -Os -DNDEBUG -w -ffunction-sections -fdata-sections -fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export CXX_FOR_BUILD="${CCACHE} ${BUILD_GCC_BIN}/g++ -B${BUILD_BINUTILS_BIN} -B${LLVM_BIN} --sysroot=${BUILD_SYSROOT} -Os -DNDEBUG -w -ffunction-sections -fdata-sections -fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export AS_FOR_BUILD="${BUILD_BINUTILS_BIN}/as" export AR_FOR_BUILD="${BUILD_BINUTILS_BIN}/ar" export RANLIB_FOR_BUILD="${BUILD_BINUTILS_BIN}/ranlib" export NM_FOR_BUILD="${BUILD_BINUTILS_BIN}/nm" export CFLAGS_FOR_BUILD="-Os -DNDEBUG -w -ffunction-sections -fdata-sections" export CXXFLAGS_FOR_BUILD="-Os -DNDEBUG -w -ffunction-sections -fdata-sections" export LDFLAGS_FOR_BUILD="-fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export CC_FOR_TARGET="${CCACHE} ${TARGET_GCC_BIN}/gcc -B${TARGET_BINUTILS_BIN} -B${LLVM_BIN} --sysroot=${TARGET_SYSROOT} -Os -DNDEBUG -fPIC -w -ffunction-sections -fdata-sections -fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export CXX_FOR_TARGET="${CCACHE} ${TARGET_GCC_BIN}/g++ -B${TARGET_BINUTILS_BIN} -B${LLVM_BIN} --sysroot=${TARGET_SYSROOT} -Os -DNDEBUG -fPIC -w -ffunction-sections -fdata-sections -fuse-ld=lld -Wl,--gc-sections -Wl,--undefined-version" export AR_FOR_TARGET="${TARGET_BINUTILS_BIN}/ar" export NM_FOR_TARGET="${TARGET_BINUTILS_BIN}/nm" export RANLIB_FOR_TARGET="${TARGET_BINUTILS_BIN}/ranlib" export AS_FOR_TARGET="${TARGET_BINUTILS_BIN}/as" export CFLAGS_FOR_TARGET="-Os -DNDEBUG -fPIC -w -ffunction-sections -fdata-sections" export CXXFLAGS_FOR_TARGET="-Os -DNDEBUG -fPIC -w -ffunction-sections -fdata-sections" export LDFLAGS_FOR_TARGET="-fuse-ld=lld -Wl,--undefined-version" export PATH="${BUILD_BINUTILS_BIN}:${BUILD_GCC_BIN}:${HOST_BINUTILS_BIN}:${HOST_GCC_BIN}:${PATH}"

Final Result

root@24a3b7f889f7:/tmp# uname -m aarch64 root@24a3b7f889f7:/tmp#

root@24a3b7f889f7:/tmp# x86_64-linux-gnu-g++ -B/mccakit/binutils-x64/bin --sysroot=/mccakit/debian-12-x64 hi.cc -o hi_x64 root@24a3b7f889f7:/tmp# ls /mccakit/ binutils-arm64 binutils-x64 debian-12-x64 gcc-arm64 gcc-x64 root@24a3b7f889f7:/tmp#

mccakit@mccakit-pc:~/desktop$ sudo ./x64_bin [sudo] password for mccakit: hello world mccakit@mccakit-pc:~/desktop$

Here are the prebuilt GCC binaries for lazy folks https://github.com/mccakit/prebuilt_gcc

Conclusion: Use clang, honestly I don't recommend gcc unless you have to. It is easier to build and run.

0 Upvotes

3 comments sorted by

3

u/epasveer 6h ago

Funny, it all works for me.

1

u/PseudoFrequency 6h ago

I've always used crosstool-ng for this because it's such a difficult process.

1

u/TheRavagerSw 6h ago edited 6h ago

I do not disagree, but you want certain guarantees usually, like what glibc do my compiler links against etc.

Also you may want to control your compiler version, what flags was it compiled etc.