Installation of GCC
If building on x86_64, change the default directory name for 64-bit
libraries to “lib”:
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esacThe GCC documentation recommends building GCC in a dedicated build directory:
mkdir -v build
cd build
Prepare GCC for compilation:
../configure --prefix=/usr \
LD=ld \
--enable-languages=c,c++ \
--enable-default-pie \
--enable-default-ssp \
--enable-host-pie \
--disable-multilib \
--disable-bootstrap \
--disable-fixincludes \
--with-system-zlibWe only enable C and C++ here to save the build time as no
packages in LFS and BLFS require GCC to compile other languages. Append
cobol for Cobol (note that it will cause GCC fail
to build on a 32-bit LFS system),
fortran for Fortran,
go for Go,
objc for Objective C,
obj-c++ for Objective C++, and/or
m2 for Modula 2 into the value of
--enable-languages option if you want to compile
programs in one or more of those languages with GCC. GCC also supports
Ada and D, but the code to support Ada or D is written in Ada or D
itself, so the support can only be built with an existing Ada or D
compiler installation and we cannot enable the support here.
The meaning of the new configure parameters:
LD=ldThis parameter makes the configure script use the ld program installed
by the Binutils package built earlier in this chapter, rather than
the cross-built version which would otherwise be used.
--disable-bootstrapBy default, the build system of GCC will bootstrap it in
3 stages unless it's built as a cross-compiler or it is being
cross-compiled. The bootstrap process is needed for robustness,
especially when upgrading GCC to a new version. In LFS we are
using a different method to bootstrap GCC (as we introduced in
), so here we don't
need the bootstrap process provided by the build system and we
disable it to significantly reduce the build time. Remove this
option when you upgrade GCC on a complete LFS system (instead of
building LFS).
--disable-fixincludesBy default, during the installation of GCC some system
headers would be “fixed” to be used with GCC. This
is not necessary for a modern Linux system, and potentially
harmful if a package is reinstalled after installing GCC. This
switch prevents GCC from “fixing” the headers.
--with-system-zlibThis switch tells GCC to link to the system installed copy of
the Zlib library, rather than its own internal copy.
![[Note]](../images/note.png)
Note
PIE (position-independent executables) are
binary programs that can be loaded anywhere in memory. Without PIE,
the security feature named ASLR (Address Space Layout Randomization)
can be applied for the shared libraries, but not for the executables
themselves. Enabling PIE allows ASLR for the executables in addition to
the shared libraries, and mitigates some attacks based on fixed
addresses of sensitive code or data in the executables.
SSP (Stack Smashing Protection) is a technique to ensure
that the parameter stack is not corrupted. Stack corruption can,
for example, alter the return address of a subroutine,
thus transferring control to some dangerous code
(existing in the program or shared libraries, or injected by the
attacker somehow).
Compile the package:
make
![[Important]](../images/important.png)
Important
In this section, the test suite for GCC is considered
important, but it takes a long time. First-time builders are
encouraged to run the test suite. The time to run the tests can be
reduced significantly by adding -jx to the make -k check
command below, where x is the number of CPU cores on your system.
GCC may need more stack space compiling some extremely complex
code patterns. As a precaution for the host distros with a tight stack
limit, explicitly set the stack size hard limit to infinite.
On most host distros (and the final LFS system) the hard limit is
infinite by default, but there is no harm done by setting it explicitly.
It's not necessary to change the stack size soft limit because GCC will
automatically set it to an appropriate value, as long as the value does
not exceed the hard limit:
ulimit -s -H unlimited
Now remove several known test failures:
sed -e '/cpython/d' -i ../gcc/testsuite/gcc.dg/plugin/plugin.exp
Test the results as a non-privileged user, but do not stop at errors:
chown -R tester .
su tester -c "PATH=$PATH make -k check"
To extract a summary of the test suite results, run:
../contrib/test_summary
To filter out only the summaries, pipe the output through
grep -A7 Summ.
Results can be compared with those located at https://www.linuxfromscratch.org/lfs/build-logs/development/ and
https://gcc.gnu.org/ml/gcc-testresults/.
The tests related to pr90579.c are known
to fail.
A few unexpected failures cannot always be avoided. In some cases
test failures depend on the specific hardware of the system.
Unless the test results are vastly different from those at the above URL,
it is safe to continue.
Install the package:
make install
The GCC build directory is owned by
tester now, and the ownership of the installed header
directory (and its content) is incorrect. Change the ownership to the
root user and group:
chown -v -R root:root \
/usr/lib/gcc/$(gcc -dumpmachine)/15.2.0/include{,-fixed}Create a symlink required by the FHS
for "historical" reasons.
ln -svr /usr/bin/cpp /usr/lib
Many packages use the name cc to call the C
compiler. We've already created cc as a symlink in
gcc-pass2, create its man page as a symlink
as well:
ln -sv gcc.1 /usr/share/man/man1/cc.1
Add a compatibility symlink to enable building programs with
Link Time Optimization (LTO):
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/15.2.0/liblto_plugin.so \
/usr/lib/bfd-plugins/Now that our final toolchain is in place, it is important to again ensure
that compiling and linking will work as expected. We do this by performing
some sanity checks:
echo 'int main(){}' | cc -x c - -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'There should be no errors,
and the output of the last command will be (allowing for
platform-specific differences in the dynamic linker name):
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
Now make sure that we're set up to use the correct start files:
grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log
The output of the last command should be:
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.0/../../../../lib/Scrt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.0/../../../../lib/crtn.o succeeded
Depending on your machine architecture, the above may differ slightly.
The difference will be the name of the directory
after /usr/lib/gcc. The important
thing to look for here is that gcc has found all three
crt*.o files under the
/usr/lib directory.
Verify that the compiler is searching for the correct header
files:
grep -B4 '^ /usr/include' dummy.log
This command should return the following output:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.0/include
/usr/local/include
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.0/include-fixed
/usr/include
Again, the directory named after your target triplet may be
different than the above, depending on your system architecture.
Next, verify that the new linker is being used with the correct search paths:
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
References to paths that have components with '-linux-gnu' should
be ignored, but otherwise the output of the last command should be:
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
A 32-bit system may use a few other directories. For example, here
is the output from an i686 machine:
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
Next make sure that we're using the correct libc:
grep "/lib.*/libc.so.6 " dummy.log
The output of the last command should be:
attempt to open /usr/lib/libc.so.6 succeeded
Make sure GCC is using the correct dynamic linker:
grep found dummy.log
The output of the last command should be (allowing for
platform-specific differences in dynamic linker name):
found ld-linux-x86-64.so.2 at /usr/lib/ld-linux-x86-64.so.2
If the output does not appear as shown above or is not received
at all, then something is seriously wrong. Investigate and retrace the
steps to find out where the problem is and correct it. Any
issues should be resolved before continuing with the process.
Once everything is working correctly, clean up the test files:
rm -v a.out dummy.log
Finally, move a misplaced file:
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib