8.29.1. Установка пакета GCC
При сборке на x86_64 измените имя каталога по умолчанию для
64-битных библиотек на «lib»:
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esac
Документация GCC рекомендует собирать GCC в отдельном каталоге:
mkdir -v build
cd build
Подготовьте GCC к компиляции:
../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 поддерживает семь различных языков программирования, но
предварительные условия для большинства из них еще не выполнены.
См. страницу
BLFS Book GCC для получения инструкций о том, как собрать все
языки, поддерживаемые GCC
Значение новых параметров настройки:
-
LD=ld
-
Этот параметр указывает скрипту configure использовать ld,
установленный программой Binutils, собранной ранее в этой
главе, а не кросс версию, которая использовалась бы в
противном случае.
-
--disable-fixincludes
-
По умолчанию во время установки GCC некоторые системные
заголовки будут «исправлены» для использования с GCC.
Это не обязательно для современной системы Linux и
потенциально опасно, если пакет будет переустановлен после
установки GCC. Этот параметр не позволяет GCC «исправлять»
заголовки.
-
--with-system-zlib
-
Этот параметр указывает GCC ссылаться на установленную в
системе копию библиотеки Zlib, а не на собственную внутреннюю
копию.
Примечание
PIE (позиционно-независимые исполняемые файлы) — это двоичные
программы, которые можно загружать в любое место памяти. Без PIE
функция безопасности под названием ASLR (рандомизация размещения
адресного пространства) может применяться к общим библиотекам, но
не к самим исполняемым файлам. Включение PIE позволяет
использовать ASLR для исполняемых файлов в дополнение к общим
библиотекам и смягчает некоторые атаки, основанные на
фиксированных адресах конфиденциального кода или данных в
исполняемых файлах.
SSP (Stack Smashing Protection - защита от разрушения стека) —
это метод, гарантирующий, что стек параметров не будет поврежден.
Повреждение стека может, например, изменить адрес возврата
подпрограммы, тем самым передав управление какому-то опасному
коду (существующему в программе или общих библиотеках или
каким-то образом внедренному злоумышленником).
Скомпилируйте пакет:
make
Важно
В этом разделе набор тестов для GCC считается важным, но занимает
много времени. Начинающим сборщикам не рекомендуется пропускать
его. Время выполнения тестов можно значительно сократить, добавив
-jx в приведенную ниже команду make
-k check, где x - количество ядер процессора в
вашей системе.
GCC может потребоваться больше места в стеке для компиляции
некоторых сложных шаблонов кода. В качестве меры предосторожности
для хост-дистрибутивов с жестким ограничением стека явно установите
неограниченный жесткий предел. В большинстве хост-дистрибутивов (и
в собранной LFS) жесткий предел по умолчанию неограничен, но нет
ничего плохого в том, чтобы установить его явно. Также нет
необходимости изменять мягкий предел размера стека, поскольку GCC
автоматически установит для него соответствующее значение, если это
значение не превышает жесткий предел:
ulimit -s -H unlimited
Теперь удалите/исправьте несколько известных ошибок тестирования:
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
Выполните тестирование от имени непривилегированного пользователя,
но не останавливайтесь на ошибках:
chown -R tester .
su tester -c "PATH=$PATH make -k check"
Чтобы получить сводку результатов набора тестов, выполните:
../contrib/test_summary
Чтобы отфильтровать только итоговую сводку, передайте вывод через
pipe grep -A7 Summ
.
Результаты можно сравнить с результатами, размещенными на https://mirror.linuxfromscratch.ru/lfs/build-logs/12.2/
и https://gcc.gnu.org/ml/gcc-testresults/.
Не всегда удается избежать неожиданных сбоев. В некоторых случаях
неудачное завершение тестов - это следствие их выполнения на
конкретном оборудовании системы. Если результаты теста не сильно
отличаются от результатов по указанному выше URL-адресу, можно
продолжать.
Установите пакет:
make install
Каталог сборки GCC теперь принадлежит пользователю tester
, и владелец каталога заголовочных файлов
(и его содержимого) указан неверно. Измените владельца на
пользователя и группу root
:
chown -v -R root:root \
/usr/lib/gcc/$(gcc -dumpmachine)/14.2.0/include{,-fixed}
Создайте символическую ссылку, требуемую FHS
по "историческим" причинам.
ln -svr /usr/bin/cpp /usr/lib
Многие пакеты используют имя cc для вызова компилятора языка
Си. Мы уже создали cc
как символическую ссылку в GCC-Проход 2, теперь создайте
символическую ссылку на его справочную страницу:
ln -sv gcc.1 /usr/share/man/man1/cc.1
Добавьте символическую ссылку совместимости, чтобы включить сборку
программ с оптимизацией времени компоновки (LTO):
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/14.2.0/liblto_plugin.so \
/usr/lib/bfd-plugins/
Теперь, когда наш окончательный набор инструментов готов, важно еще
раз убедиться, что компиляция и компоновка будут работать так, как
ожидалось. Мы сделаем это, выполнив проверку работоспособности:
echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
Ошибок быть не должно, и вывод последней команды будет (с учетом
платформо-зависимых различий в имени динамического компоновщика):
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
Теперь убедитесь, что мы настроили использование правильных
стартовых файлов:
grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log
Вывод последней команды должен быть:
/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
В зависимости от архитектуры вашего компьютера вышеуказанные
параметры могут незначительно отличаться. Разница будет заключаться
в имени каталога после /usr/lib/gcc
.
Здесь важно обратить внимание на то, что gcc нашел все три файла
crt*.o
в каталоге /usr/lib
.
Убедитесь, что компилятор ищет правильные заголовочные файлы:
grep -B4 '^ /usr/include' dummy.log
Эта команда должна вернуть следующий вывод:
#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
Опять же, имя каталога может отличаться от указанного выше, в
зависимости от архитектуры вашей системы.
Затем убедитесь, что новый компоновщик использует правильные пути
поиска:
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
Ссылки на пути, содержащие компоненты с '-linux-gnu', следует
игнорировать, но в противном случае вывод последней команды должен
быть таким:
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");
32-разрядная система может использовать несколько других каталогов.
Например, вот вывод с компьютера i686:
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");
Затем убедитесь, что мы используем правильную libc:
grep "/lib.*/libc.so.6 " dummy.log
Вывод последней команды должен быть:
attempt to open /usr/lib/libc.so.6 succeeded
Убедитесь, что GCC использует правильный динамический компоновщик:
grep found dummy.log
Вывод последней команды должен быть (с учетом различий в имени
динамического компоновщика, зависящих от платформы):
found ld-linux-x86-64.so.2 at /usr/lib/ld-linux-x86-64.so.2
Если вывод выглядит не так, как показано выше, или вообще не
получен, значит, где-то серьезная ошибка. Изучите и повторите шаги,
чтобы выяснить, в чем проблема, и исправьте ее. Любые проблемы
должны быть решены, прежде чем вы продолжите процесс.
Как только все заработает правильно, удалите тестовые файлы:
rm -v dummy.c a.out dummy.log
Наконец, переместите файл:
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib