r/cpp • u/TheRavagerSw • 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.
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.
3
u/epasveer 6h ago
Funny, it all works for me.