mirror of
https://github.com/Poltern/lfs-ru.git
synced 2024-10-18 20:00:21 +03:00
333 lines
27 KiB
XML
333 lines
27 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||
<!ENTITY % general-entities SYSTEM "../general.ent">
|
||
%general-entities;
|
||
]>
|
||
|
||
<sect1 id="ch-tools-toolchaintechnotes" xreflabel="Технические примечания по сборочным инструментам">
|
||
<?dbhtml filename="toolchaintechnotes.html"?>
|
||
|
||
<title>Технические примечания по сборочным инструментам</title>
|
||
|
||
<para>В этом разделе объясняются технические детали, лежащие в основе сборки
|
||
пакетов. Не обязательно сразу понимать все, что содержится в этом разделе.
|
||
Большая часть этой информации станет более понятной после выполнения фактической
|
||
сборки. К этому разделу можно обратиться в любое время по ходу процесса.</para>
|
||
|
||
<para>Основная задача <xref linkend="chapter-cross-tools"/> и <xref
|
||
linkend="chapter-temporary-tools"/> состоит в том, чтобы создать временную
|
||
область, содержащую заведомо исправный набор инструментов, которые можно
|
||
изолировать от хост-системы. Использовании команды <command>chroot</command>
|
||
в последующих главах, обеспечит чистую и безотказную сборку целевой системы LFS.
|
||
Процесс сборки разработан таким образом, чтобы свести к минимуму риски для
|
||
новых читателей и в то же время обеспечить наибольшую образовательную ценность.</para>
|
||
|
||
<para>Сборка инструментария основана на процессе <emphasis>кросс-компиляции</emphasis>.
|
||
Кросс-компиляция обычно используется для сборки компилятора и его инструментов для
|
||
машины, отличной от той, которая используется для сборки. Строго говоря, это не требуется
|
||
для LFS, так как машина, на которой будет работать новая система, та же, что и
|
||
используемая для сборки. Но у кросс-компиляции есть большое преимущество, заключающееся
|
||
в том, что все, что подвергается кросс-компиляции, не будет зависеть от окружения хоста.</para>
|
||
|
||
<sect2 id="cross-compile" xreflabel="About Cross-Compilation">
|
||
|
||
<title>О кросс-компиляции</title>
|
||
|
||
<note>
|
||
<para>
|
||
Книга LFS не является руководством и не содержит общего руководства по
|
||
созданию кросс (или собственного) тулчейна. Не используйте команды из книги
|
||
для кросс-тулчейна, который планруете использовать для каких-либо других целей,
|
||
кроме создания LFS, если у вас нет полного понимания, что вы делаете.
|
||
</para>
|
||
</note>
|
||
|
||
<para>Кросс-компиляция включает в себя некоторые концепции, которые сами по себе
|
||
заслуживают отдельного раздела. Хотя этот раздел можно пропустить при первом
|
||
чтении, возвращение к нему позже будет полезно для полного понимания процесса.</para>
|
||
|
||
<para>Давайте определим некоторые термины, используемые в этом контексте:</para>
|
||
|
||
<variablelist>
|
||
<varlistentry><term>сборщик</term><listitem>
|
||
<para>это машина, на которой мы создаем программы. Обратите внимание, что
|
||
этот компьютер упоминается как <quote>хост</quote> в других разделах.</para></listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry><term>хост</term><listitem>
|
||
<para>это машина/система, на которой будут выполняться встроенные программы.
|
||
Обратите внимание, что используемое здесь значение слова <quote>хост</quote>
|
||
отличается от того, которое прменяется в других разделах.</para></listitem>
|
||
</varlistentry>
|
||
|
||
<varlistentry><term>цель</term><listitem>
|
||
<para>используется только для компиляторов. Это машина, для которой компилятор
|
||
создает код. Он может отличаться как от <quote>сборщика</quote>, так и
|
||
от <quote>хоста</quote>.</para></listitem>
|
||
</varlistentry>
|
||
|
||
</variablelist>
|
||
|
||
<para>В качестве примера представим следующий сценарий (иногда называемый
|
||
<quote>канадским крестом</quote>): у нас есть компилятор на медленной
|
||
машине, назовем ее машиной A, а компилятор ccA. У нас также есть быстрая
|
||
машина (B), но без компилятора, и мы хотим создать код для другой медленной
|
||
машины (C). Чтобы собрать компилятор для машины C, у нас будет три этапа:</para>
|
||
|
||
<informaltable align="center">
|
||
<tgroup cols="5">
|
||
<colspec colnum="1" align="center" colwidth="50pt"/>
|
||
<colspec colnum="2" align="center" colwidth="50pt"/>
|
||
<colspec colnum="3" align="center" colwidth="50pt"/>
|
||
<colspec colnum="4" align="center" colwidth="50pt"/>
|
||
<colspec colnum="5" align="left" colwidth="300pt"/>
|
||
<thead>
|
||
<row><entry>Этап</entry><entry>Сборщик</entry><entry>Хост</entry>
|
||
<entry>Цель</entry><entry>Действие</entry></row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>1</entry><entry>A</entry><entry>A</entry><entry>B</entry>
|
||
<entry>сборка кросс-компилятора cc1 с использованием ccA на машине A</entry>
|
||
</row>
|
||
<row>
|
||
<entry>2</entry><entry>A</entry><entry>B</entry><entry>C</entry>
|
||
<entry>сборка кросс-компилятора cc2 с использованием cc1 на машине A</entry>
|
||
</row>
|
||
<row>
|
||
<entry>3</entry><entry>B</entry><entry>C</entry><entry>C</entry>
|
||
<entry>сборка компилятора ccC с использованием cc2 на машине B</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</informaltable>
|
||
|
||
<para>Затем все другие программы, необходимые для машины C, могут быть
|
||
скомпилированы с помощью cc2 на быстрой машине B. Обратите внимание, что
|
||
если B не может запускать программы, созданные для C, нет способа
|
||
протестировать собранные программы, пока не будет запущена сама машина C.
|
||
Например, для тестирования ccC мы можем добавить четвертый этап:</para>
|
||
|
||
<informaltable align="center">
|
||
<tgroup cols="5">
|
||
<colspec colnum="1" align="center" colwidth="50pt"/>
|
||
<colspec colnum="2" align="center" colwidth="50pt"/>
|
||
<colspec colnum="3" align="center" colwidth="50pt"/>
|
||
<colspec colnum="4" align="center" colwidth="50pt"/>
|
||
<colspec colnum="5" align="left" colwidth="300pt"/>
|
||
<thead>
|
||
<row><entry>Этап</entry><entry>Сборщик</entry><entry>Хост</entry>
|
||
<entry>Цель</entry><entry>Действие</entry></row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>4</entry><entry>C</entry><entry>C</entry><entry>C</entry>
|
||
<entry>пересобрать и протестировать ccC, используя себя на машине C</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</informaltable>
|
||
|
||
<para>В приведенном выше примере только cc1 и cc2 являются кросс-компиляторами,
|
||
то есть они создают код для машины, отличной от той, на которой они выполняются.
|
||
Компиляторы ccA и ccC создают код для машины, на которой они выполняются. Такие
|
||
компиляторы называются <emphasis>нативными</emphasis> компиляторами.</para>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="lfs-cross">
|
||
<title>Реализация кросс-компиляции для LFS</title>
|
||
|
||
<note>
|
||
<para>Почти все системы сборки используют имена вида cpu-vendor-kernel-os,
|
||
называемые машинным триплетом. Проницательный читатель может задаться
|
||
вопросом, почему <quote>триплет</quote> относится к имени из четырех компонентов.
|
||
Так сложилось исторически: изначально для однозначного обозначения машины было
|
||
достаточно трех компонентов, но с появлением новых машин и систем этого оказалось
|
||
недостаточно. Слово <quote>триплет</quote> осталось. Простой способ определить
|
||
триплет вашей машины — запустить скрипт <command>config.guess</command>, который
|
||
входит в исходный код многих пакетов. Распакуйте исходники binutils и запустите
|
||
скрипт: <userinput>./config.guess</userinput>, обратите внимание на выходные данные.
|
||
Например, для 32-разрядного процессора Intel вывод будет
|
||
<emphasis>i686-pc-linux-gnu</emphasis>. В 64-битной системе это будет
|
||
<emphasis>x86_64-pc-linux-gnu</emphasis>.</para>
|
||
|
||
<para>Также обратите внимание на название динамического компоновщика платформы,
|
||
часто называемого динамическим загрузчиком (не путать со стандартным компоновщиком
|
||
<command>ld</command>, который является частью binutils). Динамический компоновщик,
|
||
предоставляемый Glibc, находит и загружает общие библиотеки, необходимые программе,
|
||
подготавливает программу к запуску, а затем запускает ее. Имя динамического
|
||
компоновщика для 32-разрядной машины Intel — <filename
|
||
class="libraryfile">ld-linux.so.2</filename>, а для 64-разрядных систем — <filename
|
||
class="libraryfile">ld-linux-x86-64.so.2</filename>. Надежный способ определить
|
||
имя динамического компоновщика — проверить случайный двоичный файл из хост-системы,
|
||
выполнив следующую команду: <userinput>readelf -l
|
||
<name of binary> | grep interpreter</userinput> и зафиксировать результат.
|
||
Официальный источник, охватывающий все платформы, находится в файле
|
||
<filename>shlib-versions</filename> в корне дерева исходного кода Glibc.</para>
|
||
</note>
|
||
|
||
<para>Чтобы сымитировать кросс-компиляцию в LFS, имя триплета хоста немного
|
||
подкорректировали, изменив поле "vendor" в переменной <envar>LFS_TGT</envar>.
|
||
Мы также используем параметр <parameter>--with-sysroot</parameter> при сборке
|
||
кросс-компоновщика и кросс-компилятора, чтобы сообщить им, где найти необходимые
|
||
файлы хоста. Это гарантирует, что ни одна из программ, созданных в <xref
|
||
linkend="chapter-temporary-tools"/>, не сможет ссылаться на библиотеки на машине
|
||
сборки. Для корректной работы, обязательны всего два этапа, еще один
|
||
рекомендуется для тестирования:</para>
|
||
|
||
<informaltable align="center">
|
||
<tgroup cols="5">
|
||
<colspec colnum="1" align="center" colwidth="50pt"/>
|
||
<colspec colnum="2" align="center" colwidth="50pt"/>
|
||
<colspec colnum="3" align="center" colwidth="50pt"/>
|
||
<colspec colnum="4" align="center" colwidth="50pt"/>
|
||
<colspec colnum="5" align="left" colwidth="300pt"/>
|
||
<thead>
|
||
<row><entry>Этап</entry><entry>Сборщик</entry><entry>Хост</entry>
|
||
<entry>Цель</entry><entry>Действие</entry></row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>1</entry><entry>ПК</entry><entry>ПК</entry><entry>LFS</entry>
|
||
<entry>сборка кросс-компилятора cc1 с использованием cc-pc на ПК</entry>
|
||
</row>
|
||
<row>
|
||
<entry>2</entry><entry>ПК</entry><entry>LFS</entry><entry>LFS</entry>
|
||
<entry>сборка компилятора cc-lfs с использованием cc1 на ПК</entry>
|
||
</row>
|
||
<row>
|
||
<entry>3</entry><entry>LFS</entry><entry>LFS</entry><entry>LFS</entry>
|
||
<entry>пересборка и тестирование cc-lfs, используя себя в lfs</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</informaltable>
|
||
|
||
<para>В приведенной выше таблице <quote>на ПК</quote> означает, что команды
|
||
выполняются на компьютере с использованием уже установленного дистрибутива.
|
||
<quote>В lfs</quote> означает, что команды выполняются в chroot-окружении.</para>
|
||
|
||
<para>Теперь подробнее о кросс-компиляции: язык C - это не просто компилятор,
|
||
также он определяет стандартную библиотеку. В этой книге используется библиотека
|
||
GNU C под названием glibc. Эта библиотека должна быть скомпилирована для машины
|
||
lfs, то есть с использованием кросс-компилятора cc1. Но сам компилятор использует
|
||
внутреннюю библиотеку, реализующую сложные инструкции, недоступные в наборе
|
||
инструкций ассемблера. Эта внутренняя библиотека называется libgcc, и для
|
||
полноценной работы ее необходимо связать с библиотекой glibc! Кроме того,
|
||
стандартная библиотека для C++ (libstdc++) также должна быть связана с glibc.
|
||
Решение этой проблемы курицы и яйца состоит в том, чтобы сначала собрать
|
||
деградированный libgcc на основе cc1, в котором отсутствуют некоторые функции,
|
||
такие как потоки и обработка исключений, затем собрать glibc с использованием
|
||
этого деградированного компилятора (сам glibc не деградирован), а затем собрать
|
||
libstdc++. Но в этой библиотеке не будет хватать тех же функций, что и в libgcc.</para>
|
||
|
||
<para>Это не конец истории: вывод из предыдущего абзаца заключается в том, что cc1
|
||
не может собрать полнофункциональную libstdc++, но это единственный компилятор,
|
||
доступный для сборки библиотек C/C++ на этапе 2! Конечно, компилятор, созданный на
|
||
этапе 2, cc-lfs, сможет собрать эти библиотеки, но (1) система сборки GCC не
|
||
знает, что ее можно использовать на ПК, и (2) ее использование на ПК сопряжено
|
||
с риском привязки к библиотекам ПК, поскольку cc-lfs является родным компилятором.
|
||
Поэтому мы должны собрать libstdc++ позже, в chroot.</para>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="other-details">
|
||
|
||
<title>Другие детали процесса</title>
|
||
|
||
<para>Кросс-компилятор будет установлен в отдельный каталог <filename
|
||
class="directory">$LFS/tools</filename>, так как он не будет частью конечной системы.</para>
|
||
|
||
<para>Сначала устанавливается Binutils, потому что во время выполнения команды
|
||
<command>configure</command> GCC и Glibc выполняются различные тесты функций
|
||
на ассемблере и компоновщике, чтобы определить, какие программные функции
|
||
следует включить или отключить. Это важнее, чем может показаться на первый взгляд.
|
||
Неправильно настроенный GCC или Glibc может привести к незначительной поломке
|
||
сборочных инструментов, где последствия такой поломки могут проявиться ближе
|
||
к концу сборки всего дистрибутива. Сбой тестов обычно выявляет эту ошибку до того,
|
||
как будет выполнено много дополнительной работы.
|
||
</para>
|
||
|
||
<para>Binutils устанавливает свой ассемблер и компоновщик в двух местах:
|
||
<filename class="directory">$LFS/tools/bin</filename> и <filename
|
||
class="directory">$LFS/tools/$LFS_TGT/bin</filename>. Инструменты в одном
|
||
месте жестко связаны с другими. Важным аспектом компоновщика является порядок
|
||
поиска в библиотеке. Подробную информацию можно получить от <command>ld</command>,
|
||
передав ей флаг <parameter>--verbose</parameter>. Например,
|
||
<command>$LFS_TGT-ld --verbose | grep SEARCH</command> покажет текущие пути
|
||
поиска и их порядок. Он показывает, какие файлы связаны с помощью
|
||
<command>ld</command>, путем компляции фиктивной программы и передачи
|
||
параметра <parameter>--verbose</parameter> компоновщику. Например,
|
||
<command>$LFS_TGT-gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded</command>
|
||
покажет все файлы, успешно открытые во время компоновки.</para>
|
||
|
||
<para>Следующий устанавливаемый пакет — GCC. Пример того, что можно увидеть
|
||
во время запуска <command>configure</command>:</para>
|
||
|
||
<screen><computeroutput>checking what assembler to use... /mnt/lfs/tools/i686-lfs-linux-gnu/bin/as
|
||
checking what linker to use... /mnt/lfs/tools/i686-lfs-linux-gnu/bin/ld</computeroutput></screen>
|
||
|
||
<para>Это важно по причинам, упомянутым выше. Также здесь демонстрируется, что
|
||
сценарий настройки GCC не просматривает значеня переменной PATH, чтобы найти,
|
||
какие инструменты использовать. Однако во время фактической работы самого
|
||
<command>gcc</command> не обязательно используются одни и те же пути поиска.
|
||
Чтобы узнать, какой стандартный компоновщик будет использовать <command>gcc</command>,
|
||
запустите: <command>$LFS_TGT-gcc -print-prog-name=ld</command>.</para>
|
||
|
||
<para>Подробную информацию можно получить из <command>gcc</command>, передав
|
||
ему параметр <parameter>-v</parameter> при компиляции фиктивной программы.
|
||
Например, <command>gcc -v dummy.c</command> покажет подробную информацию об
|
||
этапах препроцессора, компиляции и сборки, включая указанные в <command>gcc</command>
|
||
пути поиска и их порядок.</para>
|
||
|
||
<para>Далее устанавливаются очищенные заголовочные файлы Linux API. Они позволяют
|
||
стандартной библиотеке C (Glibc) взаимодействовать с функциями, предоставляемыми
|
||
ядром Linux.</para>
|
||
|
||
<para>Следующий устанавливаемый пакет — Glibc. Наиболее важными при сборке Glibc
|
||
являются компилятор, бинарные инструменты и заголовочные файлы ядра. С компилятором,
|
||
как правило, не бывает проблем, поскольку Glibc всегда будет использовать компилятор,
|
||
указанный в параметре <parameter>--host</parameter>, переданный скрипту configure;
|
||
например, в нашем случае компилятором будет <command>$LFS_TGT-gcc</command>. С бинарными
|
||
инструментами и заголовки ядра может быть немного сложнее. Поэтому мы не рискуем и
|
||
используем доступные параметры конфигурации, чтобы обеспечить правильный выбор.
|
||
После запуска <command>configure</command> проверьте содержимое файла
|
||
<filename>config.make</filename> в каталоге <filename
|
||
class="directory">сборки</filename> на наличие всех важных деталей. Обратите внимание
|
||
на использование опции <parameter>CC="$LFS_TGT-gcc"</parameter>
|
||
(с переменной <envar>$LFS_TGT</envar>) для управления используемыми бинарными
|
||
инструментами и использование флагов <parameter>-nostdinc</parameter> и
|
||
<parameter>-isystem</parameter> для управления включаемым путем поиска компилятора.
|
||
Эти пункты подчеркивают важный аспект пакета Glibc — он очень самодостаточен
|
||
с точки зрения своего механизма сборки и, как правило, не полагается на значения по
|
||
умолчанию.</para>
|
||
|
||
<para>Как было сказано выше, затем компилируется стандартная библиотека C++, а
|
||
затем в <xref linkend="chapter-temporary-tools"/> все программы, которые необходимо
|
||
собрать. На этапе установки всех этих пакетов используется переменная DESTDIR,
|
||
чтобы программы помещались в файловую систему LFS.</para>
|
||
|
||
<para>В конце <xref linkend="chapter-temporary-tools"/> устанавливается
|
||
собственный компилятор lfs. Сначала собирается binutils-pass2 с той же
|
||
переменной <envar>DESTDIR</envar>, что и другие программы, затем собирается
|
||
второй проход GCC, опуская libstdc++ и другие не важные библиотеки. Из-за
|
||
какой-то странной логики в сценарии настройки GCC <envar>CC_FOR_TARGET</envar>
|
||
заканчивается как <command>cc</command>, когда хост совпадает с целью, но
|
||
отличается от системы сборки. Поэтому значение
|
||
<parameter>CC_FOR_TARGET=$LFS_TGT-gcc</parameter> явно указывается в
|
||
параметрах конфигурации.</para>
|
||
|
||
<para>После входа в среду chroot в <xref
|
||
linkend="chapter-chroot-temporary-tools"/> первой задачей является установка
|
||
libstdc++. Затем выполняется установка временных программ, необходимых для
|
||
правильной работы тулчейна. С этого момента основная цепочка инструментов является
|
||
самодостаточной и автономной. В <xref linkend="chapter-building-system"/>
|
||
собираются, тестируются и устанавливаются окончательные версии всех пакетов,
|
||
необходимых для полнофункциональной системы.</para>
|
||
|
||
</sect2>
|
||
|
||
</sect1>
|