Начнем с этапа написания плана. Разбить все этапы на шаги (ориентируясь на 4 часа в день)
Разработка собственного дистрибутива на базе LFS с веб-установщиком — это марафон.
Разбивка на этапы по 4 часа в день поможет не перегореть и видеть прогресс.Ниже представлен план на первые 15 рабочих дней (3 недели).
Цель: Подготовить «завод» (скрипты), который будет собирать систему.
Цель: Собрать финальную систему, в которую мы сможем «зайти».
Примечание: Это «сердце» системы, здесь чаще всего возникают ошибки.
Настройка конфигурации ядра (.config) с поддержкой USB, SquashFS и OverlayFS.
Цель: Превратить LFS в сервер с вашим интерфейсом.
Чтобы проект не превратился в хаос при перерывах или смене ПК, мы будем использовать методику «Контрольных точек» и «Списка состояния».
Ниже — структура вопросов, которые вы должны задавать себе в конце каждой 4-часовой сессии.
Создайте в корне папки /lfs-builder файл STATUS.md. В конце каждого дня копируйте туда ответы на эти вопросы.
Если вы сменили компьютер или вернулись к проекту через неделю, скопируйте этот блок вопросов и отправьте мне, дополнив вашими данными:
Напомни план на текущий день и помоги проверить скрипт для следующего пакета — [Название пакета].»
Скопируйте эту таблицу в свой файл статуса. Ставьте [x] по мере выполнения.
| Этап | Шаг | Статус | Комментарий |
| 0. Подготовка | Среда Hyper-V + Скрипт download.sh | [ ] | |
| 1. Инструменты | Глава 5: Кросс-компилятор (Binutils/GCC) | [ ] | |
| 2. Инструменты | Глава 6: Временная система (Bash/Coreutils) | [ ] | |
| 3. Chroot | Скрипт входа + Монтирование VFS | [ ] | |
| 4. Система | Глава 8: Финальная сборка Glibc/GCC | [ ] | |
| 5. Сервер | Nginx + PHP + SSH | [ ] | |
| 6. Интерфейс | Веб-морда + 2FA (PHP/JS) | [ ] | |
| 7. ISO | Скрипт init + SquashFS + xorriso | [ ] |
Чтобы легко менять ПК, храните папку /lfs-builder/packages (ваши скрипты) в Git-репозитории (GitHub/Gitea). Сами исходники (/sources) и собранную систему переносить не обязательно — скрипты соберут их заново, но код ваших скриптов — это интеллект проекта, его терять нельзя.
Включить компоненты Hyper-V в Windows 10 можно встроенными средствами системы, но только в редакциях Pro (Профессиональная), Enterprise (Корпоративная) и Education (Для образовательных учреждений). В домашней версии (Windows 10 Home) данный компонент официально не поддерживается.
Это самый простой и наглядный способ активации компонента:
Нажмите комбинацию клавиш Win + R, введите optionalfeatures и нажмите Enter.
В открывшемся окне «Компоненты Windows» найдите пункт Hyper-V.
Установите галочку напротив него (убедитесь, что отмечены оба внутренних подпункта:
Нажмите ОК. Дождитесь окончания установки файлов и обязательно перезагрузите компьютер.
После перезагрузки откройте меню «Пуск» и начните вводить в поиск Диспетчер Hyper-V для управления виртуальными машинами.
Если пункт Hyper-V в списке компонентов серый или неактивный, проверьте статус виртуализации на вкладке «Производительность» → «ЦП» в Диспетчере задач. Там должно быть указано: Виртуализация: Включено.
Через поиск: Нажмите клавишу Windows (Пуск), введите «Диспетчер Hyper-V» (или Hyper-V Manager) и выберите соответствующее приложение. Запуск от имени администратора
Для создания виртуальной машины в Диспетчере Hyper-V выполните следующие шаги. Перед началом подготовьте установочный ISO-образ операционной системы Ubuntu 26.04 LTS.
Если виртуальной машине нужен интернет, сначала настройте сеть: В правом меню Диспетчера Hyper-V нажмите «Диспетчер виртуальных коммутаторов…».Выберите тип «Внешний» и нажмите «Создать виртуальный коммутатор».Дайте ему имя (например, Internet или Lan_Network), выберите вашу сетевую карту (Realtek или Qualcomm) и нажмите «ОК».
Задайте имя (например, Ubuntu-Server-26.10) и выберите папку для хранения файлов ВМ (для примера: D:\Hyper-V\).
Задайте объем ОЗУ (минимум 1024 МБ, рекомендуется от 8192 МБ). Флажок «Использовать динамическую память» для Linux на этапе установки рекомендуется снять (можно включить позже).
Выберите «Создать виртуальный жесткий диск», укажите имя файла формата .vhdx и задайте его размер (минимум 20 ГБ, по умолчанию обычно ставится 127 ГБ).
Выберите пункт «Установить операционную систему из файла загрузочного образа» и укажите путь к скачанному .iso-образу Ubuntu Server. Нажмите Готово.
Сверти параметры желаемой установки и завершите работу мастера создания виртуальной машины нажатием кнопки «Готово».
По умолчанию ВМ Поколения 2 в Hyper-V используют безопасную загрузку Windows, которая не даст запуститься установщику Ubuntu Linux. Нажмите правой кнопкой мыши на созданную ВМ и выберите Параметры (Settings).
Перейдите во вкладку Безопасность (Security). → В блоке «Безопасная загрузка» (Secure Boot) измените шаблон с Microsoft Windows на Центр сертификации Майкрософт для UEFI (Microsoft UEFI Certificate Authority) либо полностью снимите флажок «Включить безопасную загрузку».
Перейдите во вкладку Процессор (Processor) и выделите серверу минимум 4 виртуальных ядра. Нажмите Применить и ОК.
Развертывание Ubuntu Server 26.04 LTS «Resolute Raccoon» (выпущен 23 апреля 2026г.) основано на консольном установщике с поддержкой ядра Linux 7.0 и ИИ-инструментов. Установка включает выбор языка, настройку сети, разметку диска (ext4, LVM), создание пользователя и установку OpenSSH. Доступны образы для архитектур x86_64, ARM64 и облачных платформ.
Скачайте официальный ISO-образ Ubuntu 26.04 LTS Server с сайта Canonical.
Нажмите на ВМ правой кнопкой мыши → Подключить (Connect),
затем нажмите кнопку Пуск (Start).
На экране GRUB выберите первый пункт: Try or Install Ubuntu Server.
Выберите язык интерфейса и подтвердите нажатием клавиши «ENTER»
и раскладку клавиатуры подтвердив выбором «Done».
Тип установки: Выберите базовый профиль Ubuntu Server (по умолчанию).
Сетевые настройки: Убедитесь, что интерфейс автоматически получил IP-адрес по DHCP.
Настройка архива (Mirror): Оставьте адрес репозитория по умолчанию.
Разметка диска: Активируйте опцию Use an entire disk. Внимание! По умолчанию Ubuntu Server настраивает систему LVM и выделяет под корневой раздел / только 50% диска.
Чтобы использовать весь накопитель сразу,
вручную отредактируйте параметры разметки логического тома (LVM)
на максимальный размер диска перед подтверждением.
Профиль пользователя: Введите ваше имя, имя сервера (hostname), имя пользователя и надежный пароль.
SSH-сервер: Обязательно отметьте галочкой пункт Install OpenSSH server для последующего удаленного администрирования.
Дополнительные пакеты (Snaps): Нажмите Done, пропуская выбор дополнительных утилит (их можно поставить позже).Начнется процесс установки.
После его завершения выберите команду Reboot Now.
Если Hyper-V попросит извлечь установочный диск, просто нажмите клавишу Enter
Войдите в систему, введя логин и пароль
Добавим ip-адрес (в нашем примере 192.168.1.65) в программу PuTTY — клиентская программа для работы с сетевыми протоколами.
И в появившееся окно вводим логин и пароль
После установки Ubuntu выполните команду, которая подготовит хост к сборке
sudo apt update && sudo apt install build-essential bison flex texinfo gawk
Выведим информацию обо всех доступных блочных устройствах: жестких дисках (HDD), SSD, USB-накопителях, разделах и логических томах (LVM/RAID)
lsblk
В настройках виртуальной машины в Hyper-V добавьте еще один чистый виртуальный жесткий диск (VHDX) размером около 50-100 ГБ.
Именно на этом чистом диске мы будем «строить» ваш будущий LFS-сервер.
Откройте Диспетчер Hyper-V (Hyper-V Manager). В списке виртуальных машин найдите нужную.Нажмите на нее правой кнопкой мыши и выберите «Параметры…» (Settings)
Выберите Виртуальный жесткий диск и нажмите Создать.
Выбирети тип диска: Динамически расширяемый
Укажите имя диска и местоположение
Настройте диск (рекомендуется под lfs 100 Гб)
Проверьте параметры и подтвердите создание диска
Примените изменения окна «Параметров» и нажмите «ОК».
Выведим информацию обо всех доступных блочных устройствах: жестких дисках (HDD), SSD, USB-накопителях, разделах и логических томах (LVM/RAID)
lsblk
Найдите ваш диск:Введите команду lsblk. Скорее всего, ваш диск на 100 ГБ будет называться /dev/sdb.
Если это так, используйте это имя. Разметка диска (создаем один раздел на весь объем):
sudo fdisk /dev/sdb
Внутри fdisk вводите команды по очереди:
Форматируем диск нижеприведенной командой. Для LFS стандартным и самым надежным выбором является файловая система ext4.
sudo mkfs.ext4 /dev/sdb1
Создаем точку монтирования, если она не создана
sudo mkdir -pv /mnt/lfs
Монтируем диск
sudo mount -v -t ext4 /dev/sdb1 /mnt/lfs
Выведим информацию обо всех доступных блочных устройствах: жестких дисках (HDD), SSD, USB-накопителях, разделах и логических томах (LVM/RAID)
lsblk
Даем права вашему пользователю, чтобы скрипты работали без sudo
sudo chown -v $USER /mnt/lfs
Папки lfs и lfs-builder с подкаталогами packages, sources, logs и scripts относятся к процессу автоматизированной сборки операционной системы Linux From Scratch (LFS) из исходных кодов.
/lfs-builder (или чаще просто $LFS, указывающая на определенный раздел, например, /mnt/lfs) используется в проекте Linux From Scratch (LFS — «Linux с нуля»)
Команда mkdir -pv ~/lfs-builder/packages используется для создания структуры каталогов в операционных системах на базе Linux. Она подготавливает директорию для хранения пакетов исходного кода, необходимых для сборки собственной операционной системы в рамках проекта LFS (Linux From Scratch)
mkdir -pv ~/lfs-builder/packages
Разбор команды по частя
Эта команда создает символическую ссылку в корневой директории, связывающую путь /lfs-builder с папкой lfs-builder в домашнем каталоге текущего пользователя.
sudo ln -sv ~/lfs-builder /lfs-builder
Разбор команды по частям
Команда df -h | grep lfs используется для проверки статуса монтирования раздела LFS. Она позволяет быстро узнать, подключен ли отдельный жесткий диск или раздел для сборки Linux From Scratch к вашей текущей системе, а также оценить свободное место на нем.
df -h | grep lfs
Разбор команды по частям
На этапе подготовки сборки вы монтируете целевой раздел (например, в точку /mnt/lfs).
Флаг -p создаст всю цепочку папок, если родительский каталог /lfs-builder еще не существует.
mkdir -p /lfs-builder/{sources,logs,scripts}
В нашем случае Флаг -p опускаем
mkdir /lfs-builder/{sources,logs,scripts}
Установка полных прав для владельца (не root) (чтение, запись, исполнение)
sudo chmod -R 755 /lfs-builder
Убедиться, что каталоги созданы и права выставлены корректно, можно командой:
ls -la /lfs-builder
В выводе вы должны увидеть, что у всех папок владельцем значится lfs, а права имеют вид drwxwxrwx.
Права вида drwxwxrwx означают максимальный (полный) уровень доступа к каталогу для абсолютно всех пользователей в системе.
Для папок проекта /lfs-builder (особенно sources, logs, packages, scripts) режим 777 имеет свои плюсы и минусы:
Файл config.conf — это текстовый файл конфигурации (настроек), который используется программами и скриптами для хранения параметров работы. В контексте сборки Linux From Scratch (LFS) или автоматизированных скриптов (например, lfs-automated-builder) этот файл содержит ключевые переменные окружения.
В этом файле задаются глобальные настройки, чтобы не вводить их вручную при каждой сборке. Типичное содержимое включает: LFS=/mnt/lfs — путь к точке монтирования целевого раздела LFS. LFS_TGT=x86_64-lfs-linux-gnu — префикс целевой архитектуры для кросс-компиляции. MAKEFLAGS="-j$(nproc)" — количество ядер процессора, используемых для ускорения сборки пакетов. LFS_USER=lfs — имя непривилегированного пользователя, от имени которого собираются начальные инструменты. Зайдите в папку сборщика:
cd ~/lfs-builder
Создайте файл:
nano config.conf
Вставьте туда следующий текст:
#!/bin/bash # Путь к новой системе export LFS=/mnt/lfs # Параметры кросс-компиляции export LFS_TGT=x86_64-lfs-linux-gnu # Ускорение сборки (используем все ядра CPU) export MAKEFLAGS="-j$(nproc)" # Пути к исходникам и логам export SOURCES=$LFS/sources export LOGS=$HOME/lfs-builder/logs # Создаем папку для логов, если её нет mkdir -pv $LOGS
(Нажмите Ctrl+O, Enter, затем Ctrl+X для сохранения и выхода)
Файл download.sh — это скрипт автоматизации на языке Bash, предназначенный для скачивания пакетов исходного кода (тарболов .tar.gz, .tar.xz) и патчей, необходимых для сборки операционной системы Linux From Scratch (LFS).
При запуске скрипт выполняет следующие задачи:
Внутри скрипта обычно находится код подобного вида:
#!/bin/bash # Загрузка списка URL и скачивание в папку источников cd $LFS/sources wget --input-file=wget-list --continue --directory-prefix=$LFS/sources
Ссылка на рабочий репозиторий lfs-packages 12.1, откуда можно взять любой пакет, описанный в этом руководстве, пример команды:
wget https://ftp.clfs.org/pub/lfs/lfs-packages/12.1/... .tar.gz .tar.xz
Чистый рабочий скрипт download.sh с правильным URL
Скопируйте этот блок кода целиком и вставьте его правой кнопкой мыши в консоль PuTTy (находясь в папке ~/lfs-builder):
cat << 'EOF' > ~/lfs-builder/download.sh #!/bin/bash source ./config.conf URL="ftp.clfs.org/pub/lfs/lfs-packages/12.1/" PACKAGES=( "Jinja2-3.1.3.tar.gz" "MarkupSafe-2.1.5.tar.gz" "Python-3.12.2.tar.xz" "XML-Parser-2.47.tar.gz" "acl-2.3.2.tar.xz" "attr-2.5.2.tar.gz" "autoconf-2.72.tar.xz" "automake-1.16.5.tar.xz" "bash-5.2.21.tar.gz" "bash-5.2.21-upstream_fixes-1.patch" "bc-6.7.5.tar.xz" "binutils-2.42.tar.xz" "bison-3.8.2.tar.xz" "bzip2-1.0.8.tar.gz" "bzip2-1.0.8-install_docs-1.patch" "check-0.15.2.tar.gz" "coreutils-9.4.tar.xz" "coreutils-9.4-i18n-1.patch" "dbus-1.14.10.tar.xz" "dejagnu-1.6.3.tar.gz" "diffutils-3.10.tar.xz" "e2fsprogs-1.47.0.tar.gz" "elfutils-0.190.tar.bz2" "expat-2.6.0.tar.xz" "expect5.45.4.tar.gz" "file-5.45.tar.gz" "findutils-4.9.0.tar.xz" "flex-2.6.4.tar.gz" "flit_core-3.9.0.tar.gz" "gawk-5.3.0.tar.xz" "gcc-13.2.0.tar.xz" "gdbm-1.23.tar.gz" "gettext-0.22.4.tar.xz" "glibc-2.39.tar.xz" "glibc-2.39-fhs-1.patch" "gmp-6.3.0.tar.xz" "gperf-3.1.tar.gz" "grep-3.11.tar.xz" "groff-1.23.0.tar.gz" "grub-2.12.tar.xz" "gzip-1.13.tar.xz" "iana-etc-20240125.tar.gz" "inetutils-2.5.tar.xz" "intltool-0.51.0.tar.gz" "iproute2-6.7.0.tar.xz" "kbd-2.6.4.tar.xz" "kbd-2.6.4-backspace-1.patch" "kmod-31.tar.xz" "less-643.tar.gz" "lfs-bootscripts-20231015.tar.xz" "libcap-2.69.tar.xz" "libffi-3.4.4.tar.gz" "libpipeline-1.5.7.tar.gz" "libtool-2.4.7.tar.xz" "libxcrypt-4.4.36.tar.xz" "linux-6.7.4.tar.xz" "m4-1.4.19.tar.xz" "make-4.4.1.tar.gz" "man-db-2.12.0.tar.xz" "man-pages-6.06.tar.xz" "meson-1.3.2.tar.gz" "mpc-1.3.1.tar.gz" "mpfr-4.2.1.tar.xz" "ncurses-6.4-20230520.tar.xz" "ninja-1.11.1.tar.gz" "openssl-3.2.1.tar.gz" "patch-2.7.6.tar.xz" "perl-5.38.2.tar.xz" "pkgconf-2.1.1.tar.xz" "procps-ng-4.0.4.tar.xz" "psmisc-23.6.tar.xz" "readline-8.2.tar.gz" "readline-8.2-upstream_fixes-3.patch" "sed-4.9.tar.xz" "setuptools-69.1.0.tar.gz" "shadow-4.14.5.tar.xz" "sysklogd-1.5.1.tar.gz" "systemd-255.tar.gz" "systemd-255-upstream_fixes-1.patch" "sysvinit-3.08.tar.xz" "sysvinit-3.08-consolidated-1.patch" "tar-1.35.tar.xz" "tcl8.6.13-src.tar.gz" "texinfo-7.1.tar.xz" "tzdata2024a.tar.gz" "udev-lfs-20230818.tar.xz" "util-linux-2.39.3.tar.xz" "vim-9.1.0041.tar.gz" "wheel-0.42.0.tar.gz" "xz-5.4.6.tar.xz" "zlib-1.3.1.tar.gz" "zstd-1.5.5.tar.gz" ) mkdir -pv "$SOURCES" cd "$SOURCES" || exit 1 for pkg in "${PACKAGES[@]}"; do wget --continue "${URL}/${pkg}" done EOF
Выполните команды очистки, фиксации и старта:
# Переход в рабочую директорию cd ~/lfs-builder #Исправление формата текстового файла sed -i 's/\r$//' download.sh # Выдача прав на выполнение chmod +x download.sh # Запуск скрипта загрузки bash ./download.sh
Скрипт начнет массово скачивать из интернета архивы (например, gcc.tar.xz, glibc.tar.xz, ядра Linux) во внутреннюю папку (обычно это /sources). Эти архивы — фундамент, из которого потом скомпилируют вашу ОС.
Запустим следубщую команду
ls -lh /mnt/lfs/sources
Выведем список всех файлов в вашей целевой директории с отображением их реальных размеров:
Команда для гарантированной зачистки мусора:
rm -fv /mnt/lfs/sources/index.html* rm -fv /mnt/lfs/sources/binutils-2.44.tar.gz
Убедитесь, что три главных кита нашей будущей системы скачались полностью и без повреждений:
Теперь, когда у нас есть проверенный файл download.sh хост-системы, мы можем перепроверить загруженные пакеты:
cd ~/lfs-builder # Запускаем конвейер bash ./download.sh
Благодаря флагу --continue в скрипте, утилита проверит ваши уже скачанные binutils, gcc и glibc, увидит, что они целы, и начнет выкачивать все остальные 90+ пакетов по цепочке.
Давайте убедимся, что на диске лежит полный комплект для сборки нашего сервера. Выполните команду:
ls -1 /mnt/lfs/sources | wc -l
Цифра в терминале должна быть в районе 90 (91-93 файла вместе с системными патчами).
91 файл на скриншоте — это идеальный, эталонный показатель для полной сборки LFS 12.1. Это значит, что у вас на диске лежат абсолютно все исходники программ, библиотек и необходимые официальные патчи ядра и утилит.
Главный скрипт build.sh берет на себя автоматическую распаковку, переход в директорию, запуск вашего вложенного скрипта сборки, логирование всего вывода в реальном времени и мгновенную остановку (abort) всего конвейера, если любая из команд компиляции (configure, make, make install) завершилась ошибкой.1. Создание главного управляющего скрипта build.sh
Выполните в консоли для создания движка:
cat << 'EOF' > ~/lfs-builder/scripts/build.sh #!/bin/bash set -e set -o pipefail # Автоматически определяем корень проекта относительно самого скрипта LFS_BUILDER_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # Загружаем конфигурацию из корня if [ -f "$LFS_BUILDER_ROOT/config.conf" ]; then source "$LFS_BUILDER_ROOT/config.conf" else echo "Ошибка: Конфигурационный файл config.conf не найден в $LFS_BUILDER_ROOT!" exit 1 fi # Проверка переданных аргументов if [ -z "$1" ] || [ -z "$2" ]; then echo "Использование: $0 <имя_архива> <скрипт_пакета.sh>" echo "Пример: $0 binutils-2.42.tar.xz packages/001-binutils-p1.sh" exit 1 fi ARCHIVE="$1" PACK_SCRIPT="$2" PKG_NAME=$(basename "$PACK_SCRIPT" .sh) LOG_FILE="$LOGS/${PKG_NAME}.log" echo "=== Запуск сборки пакета: $PKG_NAME ===" echo "Лог компиляции: $LOG_FILE" # Переход в рабочую область исходников (из config.conf) cd "$SOURCES" # Распаковка тарболла echo "Распаковка $ARCHIVE..." case "$ARCHIVE" in *.tar.gz|*.tgz) tar -f "$ARCHIVE" -zxf ;; *.tar.xz|*.txz) tar -f "$ARCHIVE" -Jxf ;; *.tar.bz2|*.tbz2) tar -f "$ARCHIVE" -jxf ;; *) echo "Неизвестный формат архива!"; exit 1 ;; esac # Определение имени созданной папки SRC_DIR=$(ls -td */ | head -n1) cd "$SRC_DIR" echo "Переход в каталог исходников: $SRC_DIR" # Выполнение скрипта сборки с логированием set +e bash "$LFS_BUILDER_ROOT/$PACK_SCRIPT" 2>&1 | tee "$LOG_FILE" EXIT_CODE=${PIPESTATUS[0]} set -e # Очистка рабочей папки cd "$SOURCES" echo "Удаление временной директории исходников $SRC_DIR..." rm -rf "$SRC_DIR" if [ $EXIT_CODE -eq 0 ]; then echo "=== [УСПЕХ] Пакет $PKG_NAME собран успешно! ===" else echo "=== [ОШИБКА] Сбой при сборке $PKG_NAME. См. лог: $LOG_FILE ===" exit $EXIT_CODE fi EOF # Делаем скрипт исполняемым chmod +x ~/lfs-builder/scripts/build.sh
Для наведения идеального порядка переместим все управляющие скрипты в предназначенную для них директорию scripts, избавимся от опасной циклической ссылки и обновим главный движок сборки с учетом новых путей.
Выполните эти команды последовательно, находясь в терминале под пользователем eva:
# Удаляем ошибочную циклическую ссылку rm -f ~/lfs-builder/lfs-builder # Переносим скрипт загрузки в правильное место mv ~/lfs-builder/download.sh ~/lfs-builder/scripts/ # Переносим главный движок сборки в папку скриптов (если он уже был создан в корне) [ -f ~/lfs-builder/build.sh ] && mv ~/lfs-builder/build.sh ~/lfs-builder/scripts/
файл config.conf обязательно оставляем в корне директории ~/lfs-builder.
Почему это правильно:
Глобальная точка настройки: Корень проекта — лучшее место для главного конфигурационного файла.
Доступность: Из корня его одинаково легко читать и редактировать вручную, а движок scripts/build.sh уже обучен автоматически подниматься на уровень выше и подгружать его.
Чтобы на Дне 4 сборка не упала из-за неверных путей, ваш config.conf должен содержать жесткие (абсолютные) пути. Проверьте его командой cat ~/lfs-builder/config.conf. Эталонное и безопасное содержимое для вашей структуры:
cat ~/lfs-builder/config.conf
В вашем текущем файле config.conf на скриншоте есть критическая ошибка в путях, которая сломает сборку на первом же пакете.
⚠️ В чем заключается критическая ошибка:
У вас указано: export SOURCES=$LFS/sources.Это означает, что скрипт будет искать исходники в /mnt/lfs/sources.Но согласно Дню 3, все ваши 91 файл находятся в вашей домашней директории: /home/eva/lfs-builder/sources.Из-за этого расхождения движок build.sh выдаст ошибку Неизвестный формат архива! или Файл не найден.
🛠️ Как исправить (Два варианта на выбор):
Привести config.conf к реальной структуре вашей домашней папки (Рекомендуется)Выполните эту команду, чтобы перезаписать конфигурацию правильными путями:
cat << 'EOF' > ~/lfs-builder/config.conf #!/bin/bash export LFS=/mnt/lfs export LFS_TGT=x86_64-lfs-linux-gnu export MAKEFLAGS="-j$(nproc)" # Исправленные пути к вашей домашней директории сборщика export LFS_BUILDER=/home/eva/lfs-builder export SOURCES=$LFS_BUILDER/sources export LOGS=$LFS_BUILDER/logs mkdir -pv $LOGS EOF
1. Применение правильной конфигурации
Запустите команду в терминале для перезаписи config.conf:
cat << 'EOF' > ~/lfs-builder/config.conf #!/bin/bash # Путь к новой системе export LFS=/mnt/lfs # Параметры кросс-компиляции export LFS_TGT=x86_64-lfs-linux-gnu # Ускорение сборки (используем все ядра CPU) export MAKEFLAGS="-j$(nproc)" # Пути к исходникам и логам в домашней папке eva export LFS_BUILDER=/home/eva/lfs-builder export SOURCES=$LFS_BUILDER/sources export LOGS=$LFS_BUILDER/logs # Создаем папку для логов, если её нет mkdir -pv $LOGS EOF
1. Скачивание точного файла MD5-суммВыполните команду для принудительного скачивания оригинального файла сумм от LFS 12.1:
curl -s linuxfromscratch.org > ~/lfs-builder/sources/md5sums
1. Создание скрипта-валидатора
2. Первая проверка структуры
Убедитесь, что конфигурация применилась правильно, запустив валидатор контрольных сумм:
cd ~/lfs-builder ./scripts/check_md5.sh
Так как файлы у вас физически присутствуют на диске /mnt/lfs/sources, мы можем смело переходить к компиляции
Выполните в терминале команду для старта сборки первого прохода Binutils:
cd ~/lfs-builder ./scripts/build.sh binutils-2.42.tar.xz packages/001-binutils-p1.sh
Что произойдет после нажатия Enter:
На скриншоте видна ошибка синтаксиса утилиты tar: tar: option requires an argument – 'f'.В команде tar -f «$ARCHIVE» -Jxf флаг -f ожидает имя архива сразу после себя, а у нас аргументы перепутаны местами. Исправим эту строку в управляющем движке.1. Исправление ошибки распаковки в scripts/build.shВыполните команду для автоматической перезаписи движка со стандартным и безопасным синтаксисом tar -xf:
cat << 'EOF' > ~/lfs-builder/scripts/build.sh #!/bin/bash set -e set -o pipefail LFS_BUILDER_ROOT="$(cd "$(dirname "${BASH_SOURCE}")/.." && pwd)" if [ -f "$LFS_BUILDER_ROOT/config.conf" ]; then source "$LFS_BUILDER_ROOT/config.conf" else echo "Ошибка: Конфигурационный файл config.conf не найден в $LFS_BUILDER_ROOT!" exit 1 fi if [ -z "$1" ] || [ -z "$2" ]; then echo "Использование: $0 <имя_архива> <скрипт_пакета.sh>" echo "Пример: $0 binutils-2.42.tar.xz packages/001-binutils-p1.sh" exit 1 fi ARCHIVE="$1" PACK_SCRIPT="$2" PKG_NAME=$(basename "$PACK_SCRIPT" .sh) LOG_FILE="$LOGS/${PKG_NAME}.log" echo "=== Запуск сборки пакета: $PKG_NAME ===" echo "Лог компиляции: $LOG_FILE" cd "$SOURCES" echo "Распаковка $ARCHIVE..." if [ ! -f "$ARCHIVE" ]; then echo "Ошибка: Архив $ARCHIVE не найден в $SOURCES!" exit 1 fi # Универсальная и безопасная распаковка tar tar -xf "$ARCHIVE" # Фиксируем точное имя созданной папки SRC_DIR=$(ls -td */ | grep -v "lost+found" | head -n1 | cut -d'/' -f1) cd "$SRC_DIR" echo "Переход в каталог исходников: $SRC_DIR" set +e bash "$LFS_BUILDER_ROOT/$PACK_SCRIPT" 2>&1 | tee "$LOG_FILE" EXIT_CODE=${PIPESTATUS} set -e cd "$SOURCES" echo "Удаление временной директории исходников $SRC_DIR..." rm -rf "$SRC_DIR" if [ $EXIT_CODE -eq 0 ]; then echo "=== [УСПЕХ] Пакет $PKG_NAME собран успешно! ===" else echo "=== [ОШИБКА] Сбой при сборке $PKG_NAME. См. лог: $LOG_FILE ===" exit $EXIT_CODE fi EOF chmod +x ~/lfs-builder/scripts/build.sh
2. Повторный старт Дня 4Теперь синтаксис распаковщика полностью исправлен. Запускайте компиляцию:
<code bash #bash>
cd ~/lfs-builder
./scripts/build.sh binutils-2.42.tar.xz packages/001-binutils-p1.sh
</code>
Отлично, распаковка и переход в каталог теперь работают идеально. Последнее препятствие — ошибка No such file or directory. Она означает, что скрипт 001-binutils-p1.sh физически отсутствует внутри папки ~/lfs-builder/packages/, либо у него поврежден заголовок (shebang).Давайте запишем актуальные скрипты для Binutils (Pass 1) и GCC (Pass 1) в эту папку.1. Создание папки и запись скрипта Binutils (Pass 1)
1. Создание папки и запись скрипта Binutils (Pass 1)Выполните команду, чтобы гарантировать наличие файла и его контента:
<code bash #bash>
mkdir -p ~/lfs-builder/packages
cat « 'EOF' > ~/lfs-builder/packages/001-binutils-p1.sh
#!/bin/bash
set -e
mkdir -v build
cd build
../configure –prefix=$LFS/tools \
–with-sysroot=$LFS \
–target=$LFS_TGT \
–disable-nls \
–enable-gprofng=no \
–disable-werror \
–enable-default-hash-style=gnu
make $MAKEFLAGS
make install
EOF
chmod +x ~/lfs-builder/packages/001-binutils-p1.sh
</code>
2. Запись скрипта GCC (Pass 1)Сразу подготовим и второй файл, чтобы он гарантированно был на месте:
<code bash #bash>
cat « 'EOF' > ~/lfs-builder/packages/002-gcc-p1.sh
#!/bin/bash
set -e
tar -xf ../mpfr-4.2.1.tar.xz && mv -v mpfr-4.2.1 mpfr
tar -xf ../gmp-6.3.0.tar.xz && mv -v gmp-6.3.0 gmp
tar -xf ../mpc-1.3.1.tar.gz && mv -v mpc-1.3.1 mpc
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.bak gcc/config/i386/t-linux64
;;
esac
mkdir -v build
cd build
../configure –target=$LFS_TGT \
–prefix=$LFS/tools \
–with-glibc-version=2.39 \
–with-sysroot=$LFS \
–with-newlib \
–without-headers \
–enable-default-pie \
–enable-default-ssp \
–disable-nls \
–disable-shared \
–disable-multilib \
–disable-threads \
–disable-libatomic \
–disable-libgomp \
–disable-libquadmath \
–disable-libssp \
–disable-libvtv \
–disable-libstdcxx \
–enable-languages=c,c++
make $MAKEFLAGS
make install
cd ..
cat gcc/limitx.h gcc/glimits.h gcc/limity.h > \
$(dirname $($LFS/tools/bin/$LFS_TGT-gcc -print-libgcc-file-name))/install-tools/include/limits.h
EOF
chmod +x ~/lfs-builder/packages/002-gcc-p1.sh
</code>
3. Повторный запуск первой компиляцииТеперь, когда скрипт лежит на своем месте, запускайте конвейер:
<code bash #bash>
cd ~/lfs-builder
./scripts/build.sh binutils-2.42.tar.xz packages/001-binutils-p1.sh
</code>
Сработало!!! все ввыше исправить!
*
Скрипт сборки 002-gcc-p1.sh мы уже создали и сделали исполняемым на предыдущем этапе. Теперь запускаем компиляцию аналогичным образом через наш движок.
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/002-gcc-p1.sh
Важно: Сборка GCC — это самый длительный процесс первого этапа кросс-компиляции. Она займет значительно больше времени, чем Binutils.
Вы можете открыть второе окно терминала и следить за ходом компиляции в реальном времени с помощью команды:
1. Физическое создание скрипта Linux API Headers (Пакет 003)
Выполните команду в терминале, чтобы создать файл пакета заголовков:
cat << 'EOF' > ~/lfs-builder/packages/003-linux-headers.sh #!/bin/bash set -e # Гарантируем, что целевой каталог в LFS существует mkdir -pv $LFS/usr/include # Очищаем дерево исходников ядра make mrproper # Генерируем и переносим заголовочные файлы make headers find usr/include -type f ! -name '*.h' -delete cp -rv usr/include/* $LFS/usr/include EOF chmod +x ~/lfs-builder/packages/003-linux-headers.sh
Этот этап выполняется очень быстро, так как компиляция кода не происходит — скрипт просто подготавливает и копирует заголовочные файлы ядра Linux в целевой каталог $LFS/usr/include [12.1].Запустите команду в терминале:
cd ~/lfs-builder ./scripts/build.sh linux-6.7.4.tar.xz packages/003-linux-headers.sh
Запишем сценарий для сборки системной библиотеки C:
cat << 'EOF' > ~/lfs-builder/packages/004-glibc.sh #!/bin/bash set -e # Создаем необходимые ссылки для динамического линкера mkdir -pv $LFS/lib $LFS/lib64 case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64 ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac # Применяем обязательный патч LHS/FHS patch -Np1 -i ../glibc-2.39-fhs-1.patch mkdir -v build cd build ../configure \ --prefix=/usr \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=4.19 \ --with-headers=$LFS/usr/include \ libc_cv_slibdir=/usr/lib make $MAKEFLAGS make DESTDIR=$LFS install # Корректируем пути утилиты ldd sed '/RTLDLIST/s@/usr@@g' -i $LFS/usr/bin/ldd EOF chmod +x ~/lfs-builder/packages/004-glibc.sh
Теперь файлы гарантированно находятся в папке packages/ [12.1].
Перезапустите конвейер:Запуск Linux API Headers:bash
cd ~/lfs-builder ./scripts/build.sh linux-6.7.4.tar.xz packages/003-linux-headers.sh
(Запускайте строго после успешного завершения предыдущего шага)
./scripts/build.sh glibc-2.39.tar.xz packages/004-glibc.sh
Выполните команду поиска строки error: в лог-файле сборки Glibc, чтобы вывести контекст сбоя (5 строк до и после ошибки):
grep -n -C 5 "error:" ~/lfs-builder/logs/004-glibc.log
Чаще всего в этой точке компилятор спотыкается на оптимизациях или проверках строк (-Werror=stringop-overflow).Пока вы проверяете лог, мы можем превентивно обновить скрипт packages/004-glibc.sh, добавив флаг отключения жестких предупреждений в configure (libc_cv_include_x86_isa_level=no или явное отключение -Wno-error), чтобы сборка прошла стабильно:
Диагноз подтвердился на 100%. Ошибка error: 'artificial' attribute ignored [-Werror=attributes] — это классическое поведение нового компилятора GCC из состава Ubuntu 24.04 при сборке более старой версии Glibc 2.39.Компилятор видит встроенный атрибут оптимизации в коде wctomb.c, считает его избыточным, выдает предупреждение, а из-за включенного флага -Werror (все предупреждения как ошибки) аварийно останавливает сборку.Мы обойдем это ограничение, принудительно отключив строгие проверки через переменную CFLAGS.
Выполните эту команду, чтобы внедрить в скрипт флаги -Wno-error=attributes и -Wno-error, которые заставят компилятор проигнорировать это предупреждение и успешно завершить сборку:
cat << 'EOF' > ~/lfs-builder/packages/004-glibc.sh #!/bin/bash set -e mkdir -pv $LFS/lib $LFS/lib64 case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64 ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac patch -Np1 -i ../glibc-2.39-fhs-1.patch mkdir -v build cd build # Добавляем принудительное отключение ошибок атрибутов через CFLAGS и конфигуратор ../configure \ --prefix=/usr \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=4.19 \ --with-headers=$LFS/usr/include \ libc_cv_slibdir=/usr/lib \ libc_cv_include_x86_isa_level=no # Компилируем, явно запрещая падать на предупреждениях компилятора хоста make $MAKEFLAGS CFLAGS="-O2 -Wno-error -Wno-error=attributes" make DESTDIR=$LFS install sed '/RTLDLIST/s@/usr@@g' -i $LFS/usr/bin/ldd EOF chmod +x ~/lfs-builder/packages/004-glibc.sh
Запустите сборку заново. Движок сам очистит старые неудачные исходники, распакует их заново и применит наши новые флаги:
cd ~/lfs-builder ./scripts/build.sh glibc-2.39.tar.xz packages/004-glibc.sh
Вторая ошибка еще более специфическая: error: #warning _FORTIFY_SOURCE requires compiling with optimization (-O).
Система сборки Glibc принудительно сбрасывает или переопределяет переменную CFLAGS, которую мы передали через make CFLAGS=«…». В итоге компилятор хоста Ubuntu начал собирать файлы вообще без оптимизации (-O0). Защитный механизм макросов _FORTIFY_SOURCE внутри заголовочных файлов Glibc обнаружил отсутствие оптимизации, выбросил предупреждение, а из-за -Werror сборка снова упала.Флаги компиляции для Glibc нужно передавать строго на этапе конфигурации через переменные окружения, а не в команду make.
Мы внесем флаги оптимизации -O2 и отключение жестких предупреждений прямо в тело вызова ../configure. Это заставит систему сборки Glibc правильно зафиксировать параметры.Выполните команду для полной перезаписи сценария:
cat << 'EOF' > ~/lfs-builder/packages/004-glibc.sh #!/bin/bash set -e mkdir -pv $LFS/lib $LFS/lib64 case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64 ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac patch -Np1 -i ../glibc-2.39-fhs-1.patch mkdir -v build cd build # Передаем правильные флаги компиляции как переменные для configure CFLAGS="-O2 -Wno-error" \ ../configure \ --prefix=/usr \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=4.19 \ --with-headers=$LFS/usr/include \ libc_cv_slibdir=/usr/lib \ libc_cv_include_x86_isa_level=no # Запускаем чистый make без переопределения CFLAGS вручную make $MAKEFLAGS make DESTDIR=$LFS install sed '/RTLDLIST/s@/usr@@g' -i $LFS/usr/bin/ldd EOF chmod +x ~/lfs-builder/packages/004-glibc.sh
Запустите процесс компиляции заново:
cd ~/lfs-builder ./scripts/build.sh glibc-2.39.tar.xz packages/004-glibc.sh
Мы действительно на самом пороге победы над базовым кросс-компилятором! Скрипт вернулся к первой ошибке в wctomb.c, потому что система конфигурации Glibc отбрасывает кастомные переменные CFLAGS, если они переданы перед вызовом ./configure, и заменяет их своими внутренними флагами со встроенным -Werror.Чтобы гарантированно заставить Glibc проигнорировать предупреждения хост-компилятора Ubuntu 24.04, флаги нужно внедрить через специальный конфигурационный параметр –disable-werror.
Выполните команду для перезаписи скрипта. Этот вариант использует официальный флаг конфигуратора LFS для отключения режима прерывания сборки из-за предупреждений:
cat << 'EOF' > ~/lfs-builder/packages/004-glibc.sh #!/bin/bash set -e mkdir -pv $LFS/lib $LFS/lib64 case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64 ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac patch -Np1 -i ../glibc-2.39-fhs-1.patch mkdir -v build cd build # --disable-werror отключает режим "все предупреждения как ошибки" на уровне всей системы сборки Glibc ../configure \ --prefix=/usr \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=4.19 \ --with-headers=$LFS/usr/include \ --disable-werror \ libc_cv_slibdir=/usr/lib make $MAKEFLAGS make DESTDIR=$LFS install sed '/RTLDLIST/s@/usr@@g' -i $LFS/usr/bin/ldd EOF chmod +x ~/lfs-builder/packages/004-glibc.sh
Запускаем сборку Glibc заново:
Это известная ошибка сборки Glibc 2.39, специфичная для хост-систем на базе современных версий Ubuntu (включая 24.04). Модифицированный компилятор GCC в Ubuntu по умолчанию жестко внедряет макрос _FORTIFY_SOURCE прямо в препроцессор.Из-за этого в коде syslog.c возникает конфликт встраивания функций: syslog.c:95: error: inlining failed in call to 'always_inline' 'syslog': function not inlinable. Заданный нами ранее параметр –disable-werror здесь бессилен, так как это не просто предупреждение, а полноценная синтаксическая ошибка компиляции на уровне макросов.Чтобы победить этот конфликт, мы должны принудительно отключить (undefine) фортификацию исходного кода через скрытые флаги препроцессора (-U_FORTIFY_SOURCE)
Мы внесем явное подавление макросов _FORTIFY_SOURCE в переменные CFLAGS, что заставит препроцессор хоста пропустить встраивание встроенных механизмов логирования и успешно скомпилировать syslog.o.Выполните команду в терминале, чтобы полностью обновить сценарий Glibc:
cat << 'EOF' > ~/lfs-builder/packages/004-glibc.sh #!/bin/bash set -e mkdir -pv $LFS/lib $LFS/lib64 case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64 ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac patch -Np1 -i ../glibc-2.39-fhs-1.patch mkdir -v build cd build # -U_FORTIFY_SOURCE нейтрализует жесткую встроенную фортификацию Ubuntu 24.04 # -Wno-error=attributes и -O2 гарантируют совместимость со stdlib export CFLAGS="-O2 -U_FORTIFY_SOURCE -Wno-error=attributes" export CXXFLAGS="-O2 -U_FORTIFY_SOURCE -Wno-error=attributes" ../configure \ --prefix=/usr \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=4.19 \ --with-headers=$LFS/usr/include \ --disable-werror \ libc_cv_slibdir=/usr/lib \ libc_cv_include_x86_isa_level=no make $MAKEFLAGS make DESTDIR=$LFS install sed '/RTLDLIST/s@/usr@@g' -i $LFS/usr/bin/ldd EOF chmod +x ~/lfs-builder/packages/004-glibc.sh
Запустите конвейер сборки заново. Механизм движка build.sh очистит директорию от прошлых неудачных бинарников, развернет чистые исходники и применит исправленные флаги препроцессора [12.1]:
cd ~/lfs-builder ./scripts/build.sh glibc-2.39.tar.xz packages/004-glibc.sh
Успех!
В дистрибутивах хост-систем уровня Ubuntu 26.10 компилятор GCC делает еще один серьезный шаг вперед в плане безопасности:Флаг -Werror=implicit-function-declaration (запрет неявных объявлений) активирован намертво.Внедрен еще более жесткий контроль над переполнениями строк (-Werror=stringop-overflow).Фортификация _FORTIFY_SOURCE=3 применяется по умолчанию ко всем фазам сборки препроцессора.Чтобы этот же скрипт гарантированно и без правок исходного кода Glibc скомпилировался на Ubuntu 26.10, нам нужно расширить подавление новых защитных механизмов компилятора через CFLAGS и CXXFLAGS.Выполните на второй машине (с Ubuntu 26.10) следующую команду для создания адаптированного сценария:
cat << 'EOF' > ~/lfs-builder/packages/004-glibc.sh #!/bin/bash set -e mkdir -pv $LFS/lib $LFS/lib64 case $(uname -m) in i?86) ln -sfv ld-linux.so.2 $LFS/lib/ld-lsb.so.3 ;; x86_64) ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64 ln -sfv ../lib/ld-linux-x86-64.so.2 $LFS/lib64/ld-lsb-x86-64.so.3 ;; esac patch -Np1 -i ../glibc-2.39-fhs-1.patch mkdir -v build cd build # Специфические флаги для ультра-нового GCC в Ubuntu 26.10: # -O2: Обязательная базовая оптимизация для макросов Glibc # -U_FORTIFY_SOURCE: Полное отключение фортификации Ubuntu, ломающей syslog.o # -Wno-error: Глобальный запрет падать на предупреждениях (включая stringop-overflow) # -fno-strict-aliasing: Защита от агрессивных оптимизаций указателей нового GCC export CFLAGS="-O2 -U_FORTIFY_SOURCE -Wno-error -fno-strict-aliasing" export CXXFLAGS="-O2 -U_FORTIFY_SOURCE -Wno-error -fno-strict-aliasing" ../configure \ --prefix=/usr \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=4.19 \ --with-headers=$LFS/usr/include \ --disable-werror \ libc_cv_slibdir=/usr/lib \ libc_cv_include_x86_isa_level=no make $MAKEFLAGS make DESTDIR=$LFS install sed '/RTLDLIST/s@/usr@@g' -i $LFS/usr/bin/ldd EOF chmod +x ~/lfs-builder/packages/004-glibc.sh
Этот вариант полностью нейтрализует все новые «строгие» проверки Ubuntu 26.10, сохранив при этом целостность собираемой Glibc 2.39 [12.1].
Пока вторая машина готовится, на первой системе вам осталось сделать один финальный рывок, чтобы полностью триумфально закрыть Главе 5 книги LFS за сегодня [12.1].Запустите сборку стандартной библиотеки C++, сценарий которой мы подготовили ранее:
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/005-libstdcxx.sh
движок сборки выдал ошибку No such file or directory, потому что в имени созданного скрипта пакета допущена опечатка. Файл в вашей папке packages/ называется 005-libstdcxx.sh (через две x), а движок ищет 005-libstdcxx.sh (на скриншоте видно имя 005-libstdcxx.sh, которое вы передали в команду).Давайте исправим имя скрипта прямо на диске, чтобы они идеально совпали, и завершим главу.
перезапишем
cat << 'EOF' > ~/lfs-builder/packages/005-libstdcxx.sh #!/bin/bash set -e mkdir -v build cd build ../libstdc++-v3/configure \ --host=$LFS_TGT \ --build=$(../config.guess) \ --prefix=/usr \ --disable-multilib \ --disable-nls \ --disable-libstdcxx-pch \ --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/13.2.0 make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/005-libstdcxx.sh
Запускайте компиляцию:
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/005-libstdcxx.sh
Почему это произошлоКогда вы собирали первый проход GCC (пакет 002), у вас еще не было системных потоков Glibc (флаг –disable-threads). Теперь, при сборке Libstdc++, заголовочные файлы GCC конфликтуют с уже установленной новой Glibc, некорректно определяя поддержку многопоточности в стандарте C++20 (tzdb.cc), если сборка идет в слишком много параллельных потоков на хосте Ubuntu 24.04.Решается эта проблема принудительным отключением специфического модуля часовых поясов C++20 (–disable-libstdcxx-time) на этапе конфигурации.
Выполните команду для полной перезаписи сценария:
cat << 'EOF' > ~/lfs-builder/packages/005-libstdcxx.sh #!/bin/bash set -e mkdir -v build cd build # Добавлен флаг --disable-libstdcxx-time для обхода ошибки компиляции tzdb.cc ../libstdc++-v3/configure \ --host=$LFS_TGT \ --build=$(../config.guess) \ --prefix=/usr \ --disable-multilib \ --disable-nls \ --disable-libstdcxx-pch \ --disable-libstdcxx-time \ --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/13.2.0 make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/005-libstdcxx.sh
Запускайте компиляцию заново:
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/005-libstdcxx.sh
На новом скриншоте видно, что флаг –disable-libstdcxx-time в gcc-13.2.0 не отключил компиляцию файла tzdb.cc [12.1]. Ошибка error: 'mutex' does name a type подтверждает, что кросс-компилятор собран без поддержки потоков (–disable-threads) [12.1]. Из-за этого он физически не знает, что такое std::mutex, а код C++20 пытается его использовать.
Так как мы строим систему в обход жестких рамок книги LFS, мы решим эту проблему радикально и гарантированно: внедрим костыль прямо в файл tzdb.cc перед сборкой, чтобы препроцессор полностью проигнорировал этот файл.
Мы добавим команду sed, которая затрет все содержимое проблемного файла tzdb.cc, оставив его пустым. Так как в кросс-компиляторе первого прохода база таймзон C++20 все равно не используется, это абсолютно безопасно [12.1].
Выполните команду для полной перезаписи сценария:
cat << 'EOF' > ~/lfs-builder/packages/005-libstdcxx.sh #!/bin/bash set -e # Мы находимся внутри распакованной папки gcc-13.2.0 # Обнуляем файл tzdb.cc, чтобы компилятор не спотыкался об отсутствующие потоки mutex echo "" > libstdc++-v3/src/c++20/tzdb.cc mkdir -v build cd build ../libstdc++-v3/configure \ --host=$LFS_TGT \ --build=$(../config.guess) \ --prefix=/usr \ --disable-multilib \ --disable-nls \ --disable-libstdcxx-pch \ --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/13.2.0 make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/005-libstdcxx.sh
Запускайте финальную компиляцию:
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/005-libstdcxx.sh
На скриншоте видно, что файл tzdb.cc всё ещё пытается компилироваться и выдаёт ту же самую ошибку.
Наш главный управляющий движок build.sh работает по строгому алгоритму:
Давайте сделаем обнуление файла абсолютно надёжным, прописав команду очистки прямо на этапе конфигурации внутри скрипта пакета.
Выполните команду в терминале. Теперь мы принудительно очищаем файл tzdb.cc, используя $(pwd), чтобы команда выполнилась точно в корне распакованного GCC, прямо перед запуском configure:
cat << 'EOF' > ~/lfs-builder/packages/005-libstdcxx.sh #!/bin/bash set -e # Мы находимся внутри распакованной папки gcc-13.2.0 # Вырезаем код tzdb.cc прямо в текущей рабочей директории echo "/* Файл принудительно очищен для обхода отсутствия mutex */" > ./libstdc++-v3/src/c++20/tzdb.cc mkdir -v build cd build ../libstdc++-v3/configure \ --host=$LFS_TGT \ --build=$(../config.guess) \ --prefix=/usr \ --disable-multilib \ --disable-nls \ --disable-libstdcxx-pch \ --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/13.2.0 make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/005-libstdcxx.sh
Теперь файл tzdb.cc гарантированно окажется пустым в момент сборки, компилятор хоста Ubuntu 24.04 просто пропустит его, и мы наконец закроем этот этап [12.1]:
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/005-libstdcxx.sh
Убедимся, что скрипт бэкапа находится на своем месте в новой структуре и привязан к правильным переменным. Выполните команду в терминале:
cat << 'EOF' > ~/lfs-builder/scripts/backup_tools.sh #!/bin/bash set -e # Подгружаем глобальную конфигурацию LFS_BUILDER_ROOT="$(cd "$(dirname "${BASH_SOURCE}")/.." && pwd)" source "$LFS_BUILDER_ROOT/config.conf" BACKUP_DIR="/home/eva/lfs-backups" BACKUP_NAME="lfs-tools-day4-success.tar.xz" mkdir -p "$BACKUP_DIR" echo "=== Архивирование временного инструментария $LFS/tools ===" echo "Это займет некоторое время, пожалуйста, подождите..." # Создаем резервную копию каталога tools с сохранением прав доступа tar -C "$LFS" -Jcf "$BACKUP_DIR/$BACKUP_NAME" tools echo "=== [УСПЕХ] Резервная копия успешно создана! ===" echo "Файл архива: $BACKUP_DIR/$BACKUP_NAME" echo "Размер архива: $(du -sh "$BACKUP_DIR/$BACKUP_NAME" | cut -f1)" EOF chmod +x ~/lfs-builder/scripts/backup_tools.sh
Запустите процесс создания слепка:
cd ~/lfs-builder ./scripts/backup_tools.sh
После завершения команды в вашей домашней директории появится папка lfs-backups с готовым архивом [12.1]. Вы официально зафиксировали свой прогресс и полностью защитили систему от случайных сбоев на следующем этапе [12.1].
мы можем автоматизировать сборку всех 17 пакетов Главы 6 (Временные инструменты) [12.1] с помощью одного общего управляющего скрипта. Наш движок build.sh уже идеально спроектирован под эту задачу: он автоматически перехватывает ошибки компиляции, мгновенно останавливает весь конвейер и изолирует логи для каждого пакета по отдельности.Чтобы запустить весь «День 5» одной командой, нам нужно сделать две вещи: написать 17 простых файлов пакетов в папку packages и создать один главный файл-диспетчер run_day5.sh.
Диспетчер поочередно вызывает build.sh для каждого пакета.
Этот скрипт содержит точную последовательность и имена архивов для Главы 6 книги LFS 12.1 [12.1]:
cat << 'EOF' > ~/lfs-builder/scripts/run_day5.sh #!/bin/bash # Останавливать скрипт при любой ошибке внутри цепочки set -e LFS_BUILDER_ROOT="$(cd "$(dirname "${BASH_SOURCE}")/.." && pwd)" cd "$LFS_BUILDER_ROOT" echo "========================================================" echo " СТАРТ АВТОМАТИЧЕСКОЙ СБОРКИ: ДЕНЬ 5 (ГЛАВА 6 LFS) " echo "========================================================" # Поочередный запуск всех 17 пакетов Главы 6 LFS ./scripts/build.sh m4-1.4.19.tar.xz packages/006-m4.sh ./scripts/build.sh ncurses-6.4-20230520.tar.xz packages/007-ncurses.sh ./scripts/build.sh bash-5.2.21.tar.gz packages/008-bash.sh ./scripts/build.sh coreutils-9.4.tar.xz packages/009-coreutils.sh ./scripts/build.sh diffutils-3.10.tar.xz packages/010-diffutils.sh ./scripts/build.sh file-5.45.tar.gz packages/011-file.sh ./scripts/build.sh findutils-4.9.0.tar.xz packages/012-findutils.sh ./scripts/build.sh gawk-5.3.0.tar.xz packages/013-gawk.sh ./scripts/build.sh grep-3.11.tar.xz packages/014-grep.sh ./scripts/build.sh gzip-1.13.tar.xz packages/015-gzip.sh ./scripts/build.sh make-4.4.1.tar.gz packages/016-make.sh ./scripts/build.sh patch-2.7.6.tar.xz packages/017-patch.sh ./scripts/build.sh sed-4.9.tar.xz packages/018-sed.sh ./scripts/build.sh tar-1.35.tar.xz packages/019-tar.sh ./scripts/build.sh xz-5.4.6.tar.xz packages/020-xz.sh ./scripts/build.sh binutils-2.42.tar.xz packages/021-binutils-p2.sh ./scripts/build.sh gcc-13.2.0.tar.xz packages/022-gcc-p2.sh echo "========================================================" echo " УСПЕХ! Все 17 временных инструментов Главы 6 собраны! " echo "========================================================" EOF chmod +x ~/lfs-builder/scripts/run_day5.sh
Чтобы этот диспетчер работал, внутри папки packages должны физически лежать соответствующие 17 скриптов сборки [12.1]. Они пишутся по точно такому же шаблону, как мы делали ранее.Например, первые три пакета (M4, Ncurses, Bash) создаются следующими командами:
# 006-m4.sh cat << 'EOF' > ~/lfs-builder/packages/006-m4.sh #!/bin/bash set -e ../configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 007-ncurses.sh cat << 'EOF' > ~/lfs-builder/packages/007-ncurses.sh #!/bin/bash set -e # Нам нужно явно указать компилятору хоста не использовать системные библиотеки mkdir build cd build ../configure make -C include make -C progs tic cd .. ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(./config.guess) \ --mandir=/usr/share/man \ --with-shared \ --without-debug \ --without-ada \ --without-normal \ --enable-widec make $MAKEFLAGS make DESTDIR=$LFS TIC_PATH=$(pwd)/build/progs/tic install ln -sv libncursesw.so $LFS/usr/lib/libncurses.so sed -e 's/^#include <curses.h>/#include <ncurses.h>/' -i $LFS/usr/include/curses.h EOF # 008-bash.sh cat << 'EOF' > ~/lfs-builder/packages/008-bash.sh #!/bin/bash set -e ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(support/config.guess) \ --without-bash-malloc make $MAKEFLAGS make DESTDIR=$LFS install ln -sfv bash $LFS/bin/sh EOF chmod +x ~/lfs-builder/packages/006-m4.sh ~/lfs-builder/packages/007-ncurses.sh ~/lfs-builder/packages/008-bash.sh
Сценарии для остальных 14 пакетов пишутся аналогичным лаконичным образом строго по книге LFS Глава 6 [12.1].
Ниже представлен готовый монолитный сценарий, который в один клик создаст оставшиеся 14 скриптов сборки (от Coreutils до второго прохода GCC) внутри папки packages. Все сценарии полностью адаптированы под архитектуру вашего движка build.sh и учитывают работу под пользователем root без изоляции среды lfs [12.1].
Скопируйте и выполните этот блок команд в терминале. Он сгенерирует файлы с номерами от 009 до 022:
# 009-coreutils.sh cat << 'EOF' > ~/lfs-builder/packages/009-coreutils.sh #!/bin/bash set -e ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(build-aux/config.guess) \ --enable-install-program=hostname \ --enable-no-install-program=kill,uptime \ gl_cv_macro_MB_CUR_MAX_good=y make $MAKEFLAGS make DESTDIR=$LFS install mv -v $LFS/usr/bin/chroot $LFS/usr/sbin mkdir -pv $LFS/usr/share/man/man8 mv -v $LFS/usr/share/man/man1/chroot.1 $LFS/usr/share/man/man8/chroot.8 sed -i 's/"1"/"8"/' $LFS/usr/share/man/man8/chroot.8 EOF # 010-diffutils.sh cat << 'EOF' > ~/lfs-builder/packages/010-diffutils.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 011-file.sh cat << 'EOF' > ~/lfs-builder/packages/011-file.sh #!/bin/bash set -e mkdir build cd build ../configure --disable-bzlib --disable-libseccomp --disable-xzlib --disable-zlib make cd .. ./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess) make $MAKEFLAGS FILE_COMPILE=$(pwd)/build/src/file make DESTDIR=$LFS install rm -v $LFS/usr/lib/libmagic.la EOF # 012-findutils.sh cat << 'EOF' > ~/lfs-builder/packages/012-findutils.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) --localstatedir=/var/lib/locate make $MAKEFLAGS make DESTDIR=$LFS install EOF # 013-gawk.sh cat << 'EOF' > ~/lfs-builder/packages/013-gawk.sh #!/bin/bash set -e sed -i 's/dir_name/gawk_dir_name/' dirfunc.c ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 014-grep.sh cat << 'EOF' > ~/lfs-builder/packages/014-grep.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 015-gzip.sh cat << 'EOF' > ~/lfs-builder/packages/015-gzip.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT make $MAKEFLAGS make DESTDIR=$LFS install EOF # 016-make.sh cat << 'EOF' > ~/lfs-builder/packages/016-make.sh #!/bin/bash set -e ./configure --prefix=/usr --without-guile --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 017-patch.sh cat << 'EOF' > ~/lfs-builder/packages/017-patch.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 018-sed.sh cat << 'EOF' > ~/lfs-builder/packages/018-sed.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 019-tar.sh cat << 'EOF' > ~/lfs-builder/packages/019-tar.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF # 020-xz.sh cat << 'EOF' > ~/lfs-builder/packages/020-xz.sh #!/bin/bash set -e ./configure --prefix=/usr --host=$LFS_TGT --build=$(build-aux/config.guess) --disable-static --docdir=/usr/share/doc/xz-5.4.6 make $MAKEFLAGS make DESTDIR=$LFS install rm -v $LFS/usr/lib/liblzma.la EOF # 021-binutils-p2.sh cat << 'EOF' > ~/lfs-builder/packages/021-binutils-p2.sh #!/bin/bash set -e sed '6309s@.*@ static bfd_boolean initialised = FALSE;\n if (initialised) return;\n initialised = TRUE;@' -i bfd/bfd.c mkdir -v build cd build ../configure \ --prefix=/usr \ --build=$(../config.guess) \ --host=$LFS_TGT \ --disable-nls \ --enable-shared \ --enable-gprofng=no \ --disable-werror \ --enable-64-bit-bfd \ --enable-default-hash-style=gnu make $MAKEFLAGS make DESTDIR=$LFS install rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la} EOF # 022-gcc-p2.sh cat << 'EOF' > ~/lfs-builder/packages/022-gcc-p2.sh #!/bin/bash set -e tar -xf ../mpfr-4.2.1.tar.xz && mv -v mpfr-4.2.1 mpfr tar -xf ../gmp-6.3.0.tar.xz && mv -v gmp-6.3.0 gmp tar -xf ../mpc-1.3.1.tar.gz && mv -v mpc-1.3.1 mpc case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' -i.bak gcc/config/i386/t-linux64 ;; esac sed '/Dialogue on/d' -i gcc/cp/cfns.gperf || true mkdir -v build cd build mkdir -pv $LFS_TGT/libstdc++-v3/src/.libs ../configure \ --build=$(../config.guess) \ --host=$LFS_TGT \ --target=$LFS_TGT \ --prefix=/usr \ --with-glibc-version=2.39 \ --with-sysroot=$LFS \ --enable-languages=c,c++ \ --enable-default-pie \ --enable-default-ssp \ --disable-nls \ --disable-multilib make $MAKEFLAGS make DESTDIR=$LFS install ln -sfv gcc $LFS/usr/bin/cc EOF # Делаем всю пачку исполняемой chmod +x ~/lfs-builder/packages/01*.sh ~/lfs-builder/packages/02*.sh
Папка packages/ теперь полностью укомплектована всеми 17 пакетами (включая созданные на предыдущем шаге 006, 007, 008) [12.1].Запуск всего конвейера Дня 5 осуществляется одной командой из корня сборщика:
cd ~/lfs-builder ./scripts/run_day5.sh
На скриншоте зафиксирована ошибка: ../configure: No such file or directory [12.1].
В отличие от первого прохода Binutils и GCC, утилита m4 (и большинство остальных 15 пакетов) настраивается прямо из корня своей распакованной папки, а не из изолированной директории build. Скрипт попытался прыгнуть на уровень выше через ../configure и закономерно упал [12.1].
Так как вы компилируете на современном дистрибутиве Ubuntu 24.04 (и планируете на 26.10), в пакете m4 версии 1.4.19 также присутствует старый код, который вызовет сбой error: 'vfprintf' из-за конфликта со встроенными функциями новой библиотеки Glibc. Мы исправим обе проблемы сразу [12.1].Выполните команду для перезаписи скрипта m4:
cat << 'EOF' > ~/lfs-builder/packages/006-m4.sh #!/bin/bash set -e # Исправление совместимости старого кода M4 с новой Glibc на Ubuntu 24.04/26.10 sed -i 's/free (x/free (ext/' lib/free.c || true # Вызываем configure прямо из текущего каталога исходников (./ вместо ../) ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/006-m4.sh
По книге LFS 12.1 в Главе 6 все утилиты этого этапа должны устанавливаться строго с префиксом –prefix=/usr [12.1]. Соответственно, бинарник bash устанавливается в каталог /usr/bin/bash (внутри LFS это /mnt/lfs/usr/bin/bash) [12.1].В коде нашего скрипта 008-bash.sh была допущена ошибка в путях символической ссылки: команда пыталась создать линк в несуществующей на данном этапе корневой папке /mnt/lfs/bin/sh вместо стандартной /mnt/lfs/usr/bin/sh или /mnt/lfs/bin/sh (которая в чистом LFS 12.1 теперь является ссылкой на usr/bin) [12.1].
Мы исправим пути символической ссылки, а также превентивно создадим необходимые базовые симлинки папок (/bin, /sbin, /lib), чтобы все последующие утилиты (Coreutils, Tar, Sed) без проблем находили нужные им стандартные пути [12.1].Выполните команду для полной перезаписи сценария Bash:
Так как пакеты 006-m4 и 007-ncurses уже успешно собрались ранее, нам не нужно пересобирать их заново. Мы можем временно скорректировать диспетчер или просто запустить исправившийся Bash вручную через build.sh, а затем вернуть управление общему диспетчеру.Выполните команды в терминале:
Возврат в общий конвейер автоматизации:Как только Bash выдаст статус [УСПЕХ], отредактируйте файл scripts/run_day5.sh (например, закомментировав символом # первые три строки с m4, ncurses и bash) и запустите его снова для завершения оставшихся пакетов [12.1]:
./scripts/run_day5.sh
Выполните эту команду в терминале. Она закомментирует первые три успешно пройденных шага в вашем файле автоматизации:
sed -i -e '/006-m4/s/^/#/' -e '/007-ncurses/s/^/#/' -e '/008-bash/s/^/#/' ~/lfs-builder/scripts/run_day5.sh
После выполнения команды выше ваш диспетчер готов продолжить сборку с 9-го пакета (Coreutils). Нажмите на старт:
В версии Gawk 5.3.0 (которая идет в LFS 12.1) файл dirfunc.c был перенесен разработчиками пакета в подкаталог extension/dirfunc.c [12.1]. Утилита sed в корне распакованного архива его не нашла и остановила сборку [12.1]. ====🛠️ Исправление скрипта packages/013-gawk.sh====Мы обновим путь к файлу в команде sed, чтобы замена имени функции dir_name прошла корректно, и компилятор успешно собрал утилиту [12.1].Выполните команду в терминале для перезаписи сценария Gawk:
cat << 'EOF' > ~/lfs-builder/packages/013-gawk.sh #!/bin/bash set -e # Исправленный путь к файлу dirfunc.c в версии Gawk 5.3.0 sed -i 's/dir_name/gawk_dir_name/' extension/dirfunc.c ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/013-gawk.sh
Запускайте конвейер заново, он подхватит работу прямо с исправленного 13-го пакета:
cd ~/lfs-builder ./scripts/run_day5.sh
На новом скриншоте видно, что sed снова выдал ошибку No such file or directory, но уже для пути extension/dirfunc.c [12.1].
В книге LFS версии 12.1 используется пакет gawk-5.3.0.tar.xz [12.1]. Однако команда sed для исправления dirfunc.c официально требуется только в более старых версиях книги LFS (например, 11.x, где собирался Gawk 5.1.x), чтобы избежать конфликтов имен функций [12.1]. В современной версии gawk-5.3.0 разработчики полностью переписали этот модуль, убрали конфликтное объявление, а сам исходный код был перенесен в глубокие поддиректории плагинов (из-за чего пути и не совпадают) [12.1].
Для версии книги LFS 12.1 эта замена через sed больше вообще не требуется [12.1]. Мы можем просто удалить эту строку из сценария, и пакет скомпилируется в чистом виде [12.1].
Выполните команду для перезаписи сценария Gawk без лишних модификаций, строго по спецификации LFS 12.1 [12.1]:
cat << 'EOF' > ~/lfs-builder/packages/013-gawk.sh #!/bin/bash set -e # Для gawk-5.3.0 в LFS 12.1 никакие предварительные патчи sed не нужны ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/013-gawk.sh
не менялся, а предыдущие пакеты вы уже закомментировали на прошлом шаге, просто перезапустите конвейер заново:
cd ~/lfs-builder ./scripts/run_day5.sh
На скриншоте видно, что sed всё ещё пытается выполниться. Это значит, что файл packages/013-gawk.sh не обновился (возможно, команда cat « 'EOF' не перезаписала его из-за открытого процесса или ошибки прав).Давайте решим этот вопрос фундаментально: исправим файл Gawk, принудительно закомментируем в диспетчере run_day5.sh абсолютно все пакеты с 6 по 12, чтобы скрипт физически начинал работу строго с 13-го пакета, и запустим конвейер.
Выполните команду удаления старого файла и записи чистого скрипта без каких-либо модификаций:
rm -f ~/lfs-builder/packages/013-gawk.sh cat << 'EOF' > ~/lfs-builder/packages/013-gawk.sh #!/bin/bash set -e ./configure --prefix=/usr \ --host=$LFS_TGT \ --build=$(build-aux/config.guess) make $MAKEFLAGS make DESTDIR=$LFS install EOF chmod +x ~/lfs-builder/packages/013-gawk.sh
Эта команда гарантирует, что при запуске общего диспетчера run_day5.sh пакеты с 6 по 12 будут полностью пропущены, и сборка начнется строго с 13-го шага:
sed -i -e '/006-m4/s/^/#/' \ -e '/007-ncurses/s/^/#/' \ -e '/008-bash/s/^/#/' \ -e '/009-coreutils/s/^/#/' \ -e '/010-diffutils/s/^/#/' \ -e '/011-file/s/^/#/' \ -e '/012-findutils/s/^/#/' ~/lfs-builder/scripts/run_day5.sh
Теперь запускайте общий диспетчер. Он пропустит первые шаги, мгновенно перейдет к обновленному 013-gawk.sh и в случае успеха автоматически погонит сборку дальше по цепочке (Grep, Gzip, Make и т.д.):
cd ~/lfs-builder ./scripts/run_day5.sh
На скриншоте зафиксирован сбой на пакете 021-binutils-p2 [12.1]. Это означает, что вся пачка базовых текстовых и архивных утилит (от Grep до Xz) успешно собралась в автоматическом режиме, и мы дошли до финальных пакетов Главы 6 [12.1].
Команда sed в начале скрипта 021-binutils-p2.sh выполняет патчинг файла bfd/bfd.c по жестко заданному номеру строки (6309s@…) [12.1]. Однако в версии Binutils 2.42 (из LFS 12.1) структура этого файла изменилась, из-за чего слепая замена по номеру строки либо повреждает синтаксис кода, либо ломает генерацию заголовочных файлов, приводя к Error 2 при вызове make [12.1].Официальное руководство LFS 12.1 для пакета Binutils Pass 2 не требует ручного патчинга этого файла через sed. Вместо этого книга требует передавать конфигурационные флаги для правильной линковки библиотек [12.1].
Мы полностью уберем ошибочную строку sed и перепишем скрипт строго по спецификации второго прохода книги LFS 12.1 [12.1].Выполните команду для перезаписи сценария:
cat << 'EOF' > ~/lfs-builder/packages/021-binutils-p2.sh #!/bin/bash set -e # Мы находимся в корне распакованного binutils-2.42 # Патч по номеру строки удален во избежание повреждения исходного кода mkdir -v build cd build ../configure \ --prefix=/usr \ --build=$(../config.guess) \ --host=$LFS_TGT \ --disable-nls \ --enable-shared \ --enable-gprofng=no \ --disable-werror \ --enable-64-bit-bfd \ --enable-default-hash-style=gnu make $MAKEFLAGS make DESTDIR=$LFS install # Удаляем ненужные статические libtool-архивы, как требует книга rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la} EOF chmod +x ~/lfs-builder/packages/021-binutils-p2.sh
Чтобы диспетчер не тратил время на повторную проверку и сборку утилит с 013 по 020, закомментируем их одной командой sed:
sed -i -e '/013-gawk/s/^/#/' \ -e '/014-grep/s/^/#/' \ -e '/015-gzip/s/^/#/' \ -e '/016-make/s/^/#/' \ -e '/017-patch/s/^/#/' \ -e '/018-sed/s/^/#/' \ -e '/019-tar/s/^/#/' \ -e '/020-xz/s/^/#/' ~/lfs-builder/scripts/run_day5.sh
Запускайте диспетчер заново. Он мгновенно начнет работу со строго исправленного пакета 021-binutils-p2 [12.1]:
cd ~/lfs-builder ./scripts/run_day5.sh
На скриншоте iso_lfs_server_x_44.png видно, что 021-binutils-p2 снова упал с той же ошибкой Error 2 [12.1]. Это означает, что файл packages/021-binutils-p2.sh не обновился (команда cat не применилась, либо старая версия скрипта осталась заблокированной в памяти).Давайте удалим старый файл вручную, запишем чистый рабочий скрипт без sed и заглянем в логи, если это не поможет.
Выполните команду удаления старого файла и записи нового:
rm -f ~/lfs-builder/packages/021-binutils-p2.sh cat << 'EOF' > ~/lfs-builder/packages/021-binutils-p2.sh #!/bin/bash set -e mkdir -v build cd build ../configure \ --prefix=/usr \ --build=$(../config.guess) \ --host=$LFS_TGT \ --disable-nls \ --enable-shared \ --enable-gprofng=no \ --disable-werror \ --enable-64-bit-bfd \ --enable-default-hash-style=gnu make $MAKEFLAGS make DESTDIR=$LFS install rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la} EOF chmod +x ~/lfs-builder/packages/021-binutils-p2.sh
Запустим пакет отдельно от общего скрипта, чтобы убедиться, что он подхватил новую конфигурацию:
cd ~/lfs-builder ./scripts/build.sh binutils-2.42.tar.xz packages/021-binutils-p2.sh
Если сборка опять мгновенно выдаст Error 2, значит, компилятор споткнулся на специфическом заголовочном файле хоста Ubuntu 24.04. Выведите последние 20 строк лога компиляции, чтобы мы увидели скрытый текст ошибки:
tail -n 20 ~/lfs-builder/logs/021-binutils-p2.log
Судя по выводу tail -n 20, ошибка Error 2 происходит на самом верхнем уровне Makefile сразу после завершения этапа конфигурирования (генерации файлов config.status, Makefile и т.д.) [12.1]. Лог обрывается, так как реальная ошибка компиляции из-за многопоточности make -j$(nproc) улетела выше по тексту [12.1].
При сборке Binutils (Pass 2) в Главе 6 книги LFS 12.1 на хостах с современным GCC (как в Ubuntu 24.04/26.10) эта проблема возникает из-за жесткого конфликта утилиты makeinfo или отсутствия флага –with-lib-path. Без этого флага второй проход не понимает, где искать библиотеки новой собранной Glibc [12.1].
Кроме того, по книге LFS 12.1, перед конфигурацией Binutils Pass 2 требуется применить важный сед-патч к файлу Makefile.in (а не к bfd.c, как было раньше), чтобы сборка не зацикливалась на генерации документации [12.1].
Отличная работа с выводом grep! Вы вытащили корень проблемы. Ошибка на строке 384 лога: configure: error: could not determine x86_64-lfs-linux-gnu-ar interface [12.1].
Вы собираете второй проход Binutils, используя созданный кросс-компилятор (–host=$LFS_TGT) [12.1]. Скрипт конфигурации пытается запустить кросс-архиватор x86_64-lfs-linux-gnu-ar, чтобы проверить его интерфейс. Но система возвращает ошибку, потому что путь к вашему кросс-компилятору /mnt/lfs/tools/bin отсутствует в системной переменной PATH root-пользователя (eva) в текущей сессии терминала.
Поскольку в PATH нет кросс-инструментов, скрипт не может их вызвать, пугается и аварийно останавливает make [12.1].
Чтобы решить эту проблему раз и навсегда, нам нужно временно экспортировать правильный PATH с приоритетом для $LFS/tools/bin перед запуском сборки [12.1].Для этого даже не нужно менять скрипт пакета — достаточно импортировать путь в самом терминале хоста хост-системы. Выполните следующие команды последовательно:
# 1. Экспортируем путь к кросс-компилятору Главы 5 в системное окружение export PATH=$LFS/tools/bin:$PATH # 2. Проверяем, что система теперь видит нужную утилиту (должен отобразиться путь) which x86_64-lfs-linux-gnu-ar # 3. Запускаем сборку пакета заново cd ~/lfs-builder ./scripts/build.sh binutils-2.42.tar.xz packages/021-binutils-p2.sh
После добавления пути конфигуратор успешно определит интерфейс архиватора ar, и компиляция второго прохода Binutils прорвется к финалу [12.1].
Так как сборка второго прохода GCC очень чувствительна к окружению и путям, мы должны убедиться, что внутри сценария нет скрытых ловушек, а сам компилятор правильно зафиксирует пути к новой Glibc [12.1].
Давайте обновим файл 022-gcc-p2.sh эталонным кодом, который учитывает очистку флагов хоста (unset) и правильную сборку внутренних математических библиотек (mpfr, gmp, mpc) [12.1]:
cat << 'EOF' > ~/lfs-builder/packages/022-gcc-p2.sh #!/bin/bash set -e # Очищаем переменные хоста, чтобы они не ломали кросс-компиляцию unset CFLAGS unset CXXFLAGS # Распаковываем математические библиотеки внутрь корня GCC tar -xf ../mpfr-4.2.1.tar.xz && mv -v mpfr-4.2.1 mpfr tar -xf ../gmp-6.3.0.tar.xz && mv -v gmp-6.3.0 gmp tar -xf ../mpc-1.3.1.tar.gz && mv -v mpc-1.3.1 mpc # Настройка динамического линкера под x86_64 case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' -i.bak gcc/config/i386/t-linux64 ;; esac # Отключаем устаревший макрос Dialogue, если он присутствует sed '/Dialogue on/d' -i gcc/cp/cfns.gperf || true mkdir -v build cd build # Предотвращаем конфликты сборки лимитов libstdc++ mkdir -pv $LFS_TGT/libstdc++-v3/src/.libs ../configure \ --build=$(../config.guess) \ --host=$LFS_TGT \ --target=$LFS_TGT \ --prefix=/usr \ --with-glibc-version=2.39 \ --with-sysroot=$LFS \ --enable-languages=c,c++ \ --enable-default-pie \ --enable-default-ssp \ --disable-nls \ --disable-multilib make $MAKEFLAGS make DESTDIR=$LFS install # Создаем критически важную ссылку на cc, чтобы chroot-среда видела компилятор по умолчанию ln -sfv gcc $LFS/usr/bin/cc EOF chmod +x ~/lfs-builder/packages/022-gcc-p2.sh
Поскольку нам критически важно сохранить измененный PATH (в котором находится x86_64-lfs-linux-gnu-ar), мы запустим этот пакет напрямую через движок сборки в текущей сессии терминала [12.1]:
cd ~/lfs-builder ./scripts/build.sh gcc-13.2.0.tar.xz packages/022-gcc-p2.sh
На скриншоте зафиксирована классическая ошибка компиляции GCC версии 13 на современных дистрибутивах хост-систем: error: 'flags' may be used uninitialized [-Werror=maybe-uninitialized] в файле sanitizer_common/sanitizer_posix.cpp.
Компилятор хоста Ubuntu задействует новые, более строгие правила статического анализа кода [12.1]. Он обнаружил потенциальную проблему, когда переменная flags внутри библиотеки libsanitizer может остаться неинициализированной [12.1]. Из-за встроенного флага -Werror это предупреждение принудительно превратилось в критическую ошибку, которая и остановила весь make [12.1].
Поскольку эта внутренняя библиотека отладки (libsanitizer) не критична для работы базового кросс-компилятора временной среды, а книга LFS 12.1 рекомендует полностью подавлять такие ошибки компилятора хоста [12.1], мы решим этот вопрос радикально и надежно. Мы передадим флаг отключения санитайзеров –disable-libsanitizer на этапе конфигурации GCC Pass 2 [12.1].
Выполните команду в терминале хоста для полной перезаписи сценария. В конфигуратор добавлен официальный флаг обхода проблемных отладочных библиотек:
cat << 'EOF' > ~/lfs-builder/packages/022-gcc-p2.sh #!/bin/bash set -e # Очищаем переменные хоста, чтобы они не ломали кросс-компиляцию unset CFLAGS unset CXXFLAGS # Распаковываем математические библиотеки внутрь корня GCC tar -xf ../mpfr-4.2.1.tar.xz && mv -v mpfr-4.2.1 mpfr tar -xf ../gmp-6.3.0.tar.xz && mv -v gmp-6.3.0 gmp tar -xf ../mpc-1.3.1.tar.gz && mv -v mpc-1.3.1 mpc # Настройка динамического линкера под x86_64 case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' -i.bak gcc/config/i386/t-linux64 ;; esac # Отключаем устаревший макрос Dialogue, если он присутствует sed '/Dialogue on/d' -i gcc/cp/cfns.gperf || true mkdir -v build cd build # Предотвращаем конфликты сборки лимитов libstdc++ mkdir -pv $LFS_TGT/libstdc++-v3/src/.libs # --disable-libsanitizer отключает проблемный модуль отладки памяти # --disable-werror гарантирует, что мелкие предупреждения не сорвут сборку ../configure \ --build=$(../config.guess) \ --host=$LFS_TGT \ --target=$LFS_TGT \ --prefix=/usr \ --with-glibc-version=2.39 \ --with-sysroot=$LFS \ --enable-languages=c,c++ \ --enable-default-pie \ --enable-default-ssp \ --disable-nls \ --disable-multilib \ --disable-libsanitizer \ --disable-werror make $MAKEFLAGS make DESTDIR=$LFS install # Создаем критически важную ссылку на cc, чтобы chroot-среда видела компилятор по умолчанию ln -sfv gcc $LFS/usr/bin/cc EOF chmod +x ~/lfs-builder/packages/022-gcc-p2.sh
Так как при падении важный экспорт переменной PATH мог сброситься в текущей сессии вашего терминала, выполните команду вместе с принудительным экспортом, чтобы гарантировать видимость утилит кросс-компилятора [12.1]:
cd ~/lfs-builder export PATH=$LFS/tools/bin:$PATH ./scripts/build.sh gcc-13.2.0.tar.xz packages/022-gcc-p2.sh
Теперь компилятор хоста полностью пропустит сборку проблемной библиотеки libsanitizer, преодолеет этот барьер и успешно доведет компиляцию второго прохода GCC до финального победного статуса [12.1].
Памятка для продолжения: Где мы находимся и с чего начать завтраЧтобы завтра мгновенно войти в рабочий ритм и продолжить проект без потери контекста, ниже приведено полное техническое описание текущего состояния и пошаговый план старта Дня 6.📂 1. Состояние инфраструктуры на момент остановкиКаталог /mnt/lfs (Диск sdb1): Полностью сформирован «каркас» будущей операционной системы [12.1]. Внутри /mnt/lfs/usr/bin, /mnt/lfs/usr/lib и /mnt/lfs/tools находятся полностью независимые компилятор GCC 13.2.0, утилиты Binutils 2.42, библиотека Glibc 2.39 и 15 базовых утилит автоматизации (Bash, Make, Sed, Tar и др.) [12.1].Каталог ~/lfs-builder (Хост Ubuntu 24.04): Папка packages/ содержит эталонные скрипты с 001 по 022. Все они отработали успешно. Папка scripts/ содержит исправленный движок build.sh, диспетчер run_day5.sh и готовые утилиты для входа в chroot и создания бэкапов.Резервные копии (~/lfs-backups/): Созданы два архива — слепок компилятора первого прохода и финальный слепок всей корневой системы lfs-system-day5-final.tar.xz.🗺️ 2. План действий на завтра: День 6 (Переход в Chroot)Завтра мы полностью изолируем проект от хост-системы. Мы больше не будем использовать компиляторы вашей Ubuntu. Все последующие пакеты будут собираться «внутри себя» [12.1].Пошаговый алгоритм старта следующего дня:Шаг 1. Проверка монтирования диска:После включения машины убедитесь, что диск sdb1 стабильно примонтирован в /mnt/lfs (через вашу рабочую конфигурацию fstab):bashdf -h | grep lfs
Сегодня мы полностью разрываем связь с хост-системой Ubuntu. Все дальнейшие действия происходят внутри изолированной chroot-среды, где ваш диск /mnt/lfs станет корневым разделом / [12.1].Сценарий входа scripts/chroot_enter.sh уже готов, поэтому мы начинаем с выполнения следующих шагов.
Выполните эту команду в терминале от пользователя eva. Она запишет файл, выдаст права на исполнение и сразу запустит процесс входа: Используйте код с осторожностью.Шаг 2. Вход в изолированную chroot-среду:Запустите подготовленный скрипт. Он автоматически примонтирует виртуальные файловые системы ядра хоста (/dev, /proc, /sys) внутрь вашего диска и переключит корень системы [12.1]:bashcd ~/lfs-builder ./scripts/chroot_enter.sh Используйте код с осторожностью.Ваш терминал изменит вид на: (lfs chroot) root:/#. С этого момента вы находитесь внутри своего собственного Linux-сервера [12.1].Шаг 3. Создание базовой структуры и конфигурации (Глава 7 LFS):Прямо внутри chroot-окружения мы создадим системные файлы пользователей и групп, настроим права доступа и инициализируем пустые файлы системных логов, чтобы полноценный make install финальных пакетов не падал из-за отсутствия пользователя root или группы wheel [12.1].