8.29.1. Installation of GCC
On ARM64 hosts, set the default directory name for 64-bit libraries
to “lib”:
sed -e '/lp64=/s/lib64/lib/' \
-i.orig gcc/config/aarch64/t-aarch64-linux
The 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-zlib
GCC supports seven different computer languages, but the
prerequisites for most of them have not yet been installed. See the
BLFS Book GCC page for instructions on how to build all of
GCC's supported languages.
The meaning of the new configure parameters:
-
LD=ld
-
This 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-fixincludes
-
By 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-zlib
-
This switch tells GCC to link to the system installed copy of
the Zlib library, rather than its own internal copy.
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
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/fix 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/.
On ARM64, many tests in the c-c++-common/hwasan
, the gcc.target/aarch64/sve/acle
directory, the
gcc.target/aarch64/sme
directory, and
the g++.dg/modules
directory are
known to fail. The tests named memset-strict-align-1.c
, ssa-dom-thread-7.c
, and pr113618.c
are also 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)/14.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)/14.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(){}' > dummy.c
cc dummy.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: /lib/ld-linux-aarch64.so.1]
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/aarch64-unknown-linux-gnu/14.2.0/../../../../lib/Scrt1.o succeeded
/usr/lib/gcc/aarch64-unknown-linux-gnu/14.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/aarch64-unknown-linux-gnu/14.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/aarch64-unknown-linux-gnu/14.2.0/include
/usr/local/include
/usr/lib/gcc/aarch64-unknown-linux-gnu/14.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/aarch64-unknown-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/aarch64-unknown-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-aarch64.so.1 at /usr/lib/ld-linux-aarch64.so.1
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 dummy.c 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