8.29.1. 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
;;
esac
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.
One set of tests in the GCC test suite is known to exhaust the
default stack, so increase the stack size prior to running the
tests:
ulimit -s 32768
Now remove/fix several known test failures:
sed -e '/cpython/d' -i ../gcc/testsuite/gcc.dg/plugin/plugin.exp
sed -e 's/no-pic /&-no-pie /' -i ../gcc/testsuite/gcc.target/i386/pr113689-1.c
sed -e 's/300000/(1|300000)/' -i ../libgomp/testsuite/libgomp.c-c++-common/pr109062.c
sed -e 's/{ target nonpic } //' \
-e '/GOTPCREL/d' -i ../gcc/testsuite/gcc.target/i386/fentryname3.c
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/12.2-rc1/
and https://gcc.gnu.org/ml/gcc-testresults/.
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: /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/14.2.0/../../../../lib/Scrt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/14.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-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/x86_64-pc-linux-gnu/14.2.0/include
/usr/local/include
/usr/lib/gcc/x86_64-pc-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/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 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