Linux From Scratch (LFS) 종합 가이드

LFS 13.0-systemd(2026년 3월 릴리스) 기반으로 리눅스 시스템을 처음부터 빌드하는 과정을 심층 분석합니다. 크로스 컴파일(Cross Compilation) 이론과 build·host·target 트리플렛, Binutils/GCC/Glibc의 Pass 1·2 구축, 임시 도구 크로스 컴파일, Chroot 환경 진입, 83개 패키지를 포함한 기본 시스템 소프트웨어 설치, 커널 컴파일, GRUB 부트로더(Bootloader), systemd 설정, 패키지 관리 전략, 트러블슈팅까지 LFS의 모든 것을 다룹니다.

전제 조건: GCC와 빌드 시스템(Build System), Binutils 문서를 먼저 읽으세요. LFS는 GCC 크로스 컴파일러 구성과 Makefile/configure 스크립트 이해가 필수적입니다.
일상 비유: LFS는 부품을 하나씩 골라 자동차를 조립하는 것과 비슷합니다. 완성차(Ubuntu, Fedora)를 사는 대신, 엔진(커널), 변속기(glibc), 프레임(coreutils) 등을 직접 선택하고 조립하여 나만의 맞춤형 시스템을 만듭니다.

핵심 요약

  • LFS (Linux From Scratch) — 소스 코드에서 리눅스 시스템 전체를 직접 빌드하는 프로젝트. 패키지 매니저 없이 83개 패키지를 순서대로 컴파일하여 부팅 가능한 최소 시스템을 만듭니다.
  • 크로스 컴파일러 — 현재 시스템(호스트)과 다른 환경에서 실행될 바이너리를 생성하는 컴파일러. LFS에서는 호스트 오염을 방지하기 위해 같은 아키텍처라도 크로스 컴파일러를 사용합니다.
  • 툴체인 — 소스 코드를 실행 가능한 바이너리로 변환하는 도구 집합. Binutils(as, ld) + GCC(cc1, cc1plus) + Glibc(libc.so) + Libstdc++로 구성됩니다.
  • Sysroot — 크로스 컴파일러가 타겟 시스템의 헤더와 라이브러리를 찾는 최상위 디렉토리. --with-sysroot=$LFS로 지정하여 호스트의 /usr/lib 대신 $LFS/usr/lib를 참조합니다.
  • Chroot — chroot 시스템 콜(System Call)로 루트 디렉토리를 변경하여, 빌드 중인 LFS 파티션을 마치 독립 시스템처럼 사용하는 격리(Isolation) 환경입니다.

단계별 이해

  1. 호스트 준비
    호스트 시스템 요구사항 확인, LFS 파티션 생성·마운트(Mount), lfs 사용자 생성, 환경 변수 설정을 먼저 끝냅니다.

    왜 별도 파티션인가? LFS 빌드 결과물은 $LFS 디렉토리에 축적됩니다. 나중에 chroot로 이 경로를 루트(/)로 삼기 위해 독립된 파티션(또는 디렉토리)이 필요합니다. 별도의 lfs 사용자를 만드는 이유는 크로스 컴파일 단계에서 실수로 root 권한으로 호스트를 오염시키는 것을 방지하기 위해서입니다.

  2. 크로스 툴체인 구축
    Binutils Pass 1 → GCC Pass 1 → Linux API 헤더 → Glibc → Libstdc++ 순서로 크로스 컴파일러를 만듭니다.

    왜 크로스 컴파일러가 필요한가? 호스트의 GCC로 직접 빌드하면 호스트의 헤더와 라이브러리가 LFS 바이너리에 섞여 들어올 위험이 있습니다. x86_64-lfs-linux-gnu-gcc처럼 트리플렛(Triplet)이 다른 크로스 컴파일러를 만들면, 이 컴파일러는 $LFS/usr/include와 $LFS/usr/lib만 참조하므로 호스트 오염이 원천 차단됩니다.

  3. 임시 도구 크로스 컴파일
    크로스 툴체인으로 m4, ncurses, bash 등 기본 유틸리티와 Binutils/GCC Pass 2 네이티브 컴파일러를 준비합니다.

    왜 임시 도구가 따로 필요한가? Chroot 환경 안에는 호스트의 bash, make, grep이 존재하지 않습니다. Chroot 진입 전에 이 도구들을 $LFS/usr/bin에 채워두어야 빌드 스크립트가 정상 동작합니다. Pass 2 컴파일러는 Glibc를 완전히 인식하므로, 이후 모든 패키지를 "진짜 타겟 환경"에서 컴파일할 수 있게 됩니다.

  4. Chroot 진입
    chroot로 격리 환경에 들어가 호스트 오염 없이 최종 빌드 작업을 수행합니다.

    chroot란 무엇인가? chroot(2) 시스템 콜(System Call)은 현재 프로세스의 루트 디렉토리를 $LFS로 교체합니다. 이 시점부터 /usr/lib/libc.so는 실제로 $LFS/usr/lib/libc.so를 가리키며, 호스트의 파일 시스템은 완전히 보이지 않습니다. 커널 인터페이스(/proc, /sys, /dev)는 바인드 마운트(Bind Mount)로 Chroot 안에 제공합니다.

  5. 최종 시스템 완성
    83개 패키지 설치, 커널 컴파일, GRUB·systemd 구성을 거쳐 부팅 가능한 시스템을 완성합니다.

    최종 빌드의 특징: Chroot 안에서 설치되는 패키지는 모두 LFS 자체 툴체인을 사용하므로 호스트 GCC나 호스트 glibc와 완전히 무관합니다. 커널 컴파일 후 /boot/vmlinuz를 배치하고, GRUB 부트로더가 이를 로드하면 완전히 독립된 LFS 시스템으로 부팅할 수 있습니다.

LFS 개요와 철학

Linux From Scratch(LFS)는 소스 코드만으로 리눅스 시스템 전체를 직접 빌드하는 교육용 프로젝트입니다. 1999년 Gerard Beekmans가 시작했으며, 리눅스 시스템의 내부 구조를 이해하는 가장 효과적인 방법으로 널리 인정받고 있습니다.

왜 LFS인가?

리눅스 시스템 계층 구조

LFS를 시작하기 전에 "리눅스 시스템은 어떤 계층으로 이루어지는가"를 파악하면 각 패키지의 역할과 빌드 순서를 훨씬 직관적으로 이해할 수 있습니다. LFS는 이 계층 전체를 소스 코드에서 직접 구축합니다.

리눅스 시스템 계층 구조 — 위로 갈수록 상위 계층, LFS는 커널부터 Shell + 유틸리티까지 구축하고 응용 프로그램은 BLFS 단계에서 추가 리눅스 시스템 계층 구조 위로 갈수록 상위 계층 — 상위 계층이 아래 계층의 서비스를 사용합니다 계층 (Layer) 역할 (Role) 대표 파일 (Files) 응용 프로그램 Applications 사용자가 직접 실행하는 프로그램 BLFS 범위 — LFS 이후 단계 vim, python, firefox 응용 계층 예시 Shell + 유틸리티 Shell & Utilities 사용자와 상호작용하는 명령어 인터페이스 LFS 83개 패키지에 포함 bash, ls, grep, make 셸과 기본 명령어 C 표준 라이브러리 glibc 시스템 콜 래퍼(Wrapper), C 표준 함수 모든 응용 프로그램이 의존 libc.so, ld-linux.so C 라이브러리 핵심 파일 Linux API 헤더 Kernel Headers 시스템 콜 번호·구조체 정의 glibc가 이 헤더를 참조 unistd.h, sys/types.h 헤더 파일 예시 리눅스 커널 Linux Kernel 하드웨어를 직접 제어하는 커널 드라이버·스케줄러·메모리 관리 vmlinuz 커널 부팅 이미지 LFS 구축 범위 — 커널부터 Shell + 유틸리티까지 4개 계층을 소스에서 직접 빌드 BLFS 범위 — 응용 프로그램 (LFS 완성 후 선택적으로 빌드)
리눅스 시스템 계층 구조 — 위로 갈수록 상위 계층, LFS는 커널부터 Shell + 유틸리티까지 구축하고 응용 프로그램은 BLFS 단계에서 추가합니다
계층대표 구성요소LFS에서의 역할빌드 시점
리눅스 커널vmlinuz하드웨어를 직접 제어하는 핵심 소프트웨어최종 단계 (chroot 내부)
Linux API 헤더unistd.h, sys/types.h시스템 콜 번호·구조체 정의 — glibc가 이것을 참조크로스 툴체인 3단계
C 표준 라이브러리libc.so, ld-linux.so시스템 콜 래퍼(Wrapper) — 모든 응용 프로그램이 의존크로스 툴체인 4단계
Shell + 유틸리티bash, coreutils사용자 명령어 인터페이스 — LFS 83개 패키지에 포함최종 시스템 설치
응용 프로그램vim, python실제 사용자 작업 소프트웨어 — BLFS 범위BLFS (LFS 이후)

LFS 프로젝트 패밀리

프로젝트설명기반
LFS기본 리눅스 시스템 빌드 (이 문서의 주제)소스 코드
BLFSBeyond LFS — X Window, 네트워크, 데스크톱 환경 등 확장LFS 위에 추가
CLFSCross LFS — 다른 아키텍처용 크로스 빌드 (ARM, MIPS 등)크로스 컴파일
ALFSAutomated LFS — 스크립트 자동화 빌드LFS 자동화
Hints커뮤니티 팁 모음 (패키지 관리, 최적화 등)LFS 보조
SBU (Standard Build Unit): LFS에서 빌드 시간을 측정하는 상대적 단위입니다. Binutils Pass 1의 빌드 시간을 1 SBU로 정의하고, 다른 패키지의 빌드 시간을 이 기준으로 표현합니다. 예를 들어, GCC가 12 SBU라면 Binutils의 약 12배 시간이 걸린다는 의미입니다. 실제 소요 시간은 CPU 성능·코어 수·메모리 속도 등 하드웨어에 따라 크게 달라집니다.
항목LFS 13.1-systemd (현재 최신)LFS 13.0-systemd (이전 안정)
릴리스 날짜2026년 9월 1일2026년 3월 5일
리눅스 커널7.1.86.18.10
GCC16.2.015.2.0
Glibc2.442.43
Binutils2.472.46
init 시스템systemd 261.2systemd 259.1
업데이트 패키지 수46개 (13.0 대비)36개 (12.4 대비)
예상 빌드 시간약 30~50 SBU (하드웨어에 따라 상이)약 30~50 SBU
필요 디스크 공간최소 30GB (소스 + 빌드)최소 30GB
버전 이력 요약 (2026-09 기준):
  • 13.1 (2026-09-01) — 현재 안정 릴리스. Binutils 2.47, GCC 16.2.0, Glibc 2.44, 커널 7.1.8, systemd 261.2 기준. 46개 패키지가 업데이트·추가되었으며 총 200여 개 커밋이 반영되었습니다.
  • 13.0 (2026-03-05) — 직전 안정 릴리스. Binutils 2.46, Glibc 2.43, 커널 6.18.10 기준. expat·glibc·openssl·Python·vim·zlib 등 주요 패키지 보안 업데이트 포함. 총 100여 개 커밋.
  • 12.4 (2025-09-01) — Binutils 2.45, GCC 15.2.0, Glibc 2.42, 커널 6.16.1. 49개 패키지 갱신, 146개 커밋.
  • 12.3 (2025-03-05) — Binutils 2.44, Glibc 2.41, 커널 6.13.2. 45개 패키지 갱신.
  • SysVinit 에디션 중단 — 13.0부터 LFS 팀은 Systemd 에디션만 정기 갱신합니다. SysV 에디션은 12.4에서 동결되었습니다 (13.0 릴리스 공지 기준).

LFS 릴리스 주기는 대략 6개월이며, 홀수 달(3월/9월)에 릴리스되는 경향이 있습니다. linuxfromscratch.org/lfs/news.html에서 최신 릴리스 노트를 확인하세요.

LFS 전체 빌드 프로세스 7단계 플로우 — 호스트 준비부터 부팅 가능 시스템까지 LFS 전체 빌드 프로세스 호스트 준비부터 부팅 가능 시스템까지 7단계 크로스 컴파일 영역 네이티브 빌드 영역 1단계 호스트 준비 호스트 요구사항 확인 2단계 파티션 설정 LFS 파티션·마운트 3단계 크로스 툴체인 툴체인 Pass 1 빌드 4단계 임시 도구 임시 유틸리티 빌드 5단계 Chroot 진입 격리 환경으로 전환 6단계 시스템 빌드 83개 패키지 설치 7단계 부팅 설정 커널·GRUB·systemd Ch.2 Ch.3-4 Ch.5 Ch.6 Ch.7 Ch.8 Ch.9-11
LFS 전체 빌드 프로세스(Process) 7단계 — 호스트 준비부터 부팅 가능 시스템까지
LFS vs 일반 배포판 비교 — 7개 항목별 장단점 대조 LFS vs 일반 배포판 비교 용도에 따라 유리한 쪽은 달라집니다 항목 LFS (Linux From Scratch) 일반 배포판 (Ubuntu 등) 빌드 방식 소스에서 직접 컴파일 사전 빌드 바이너리 설치 패키지 수 83개 핵심 패키지만 포함 수만 개 패키지 저장소 빌드/설치 시간 수 시간 ~ 수일 10 ~ 30분 커스터마이징 완전한 자유 (소스 레벨) 설정 옵션 내에서 제한적 학습 가치 시스템 내부 구조 이해 내부 구조 파악 어려움 디스크 사용 최소 (~500MB) 불필요 패키지 포함 (수 GB) 업데이트/유지보수 수동 소스 빌드 필요 패키지 매니저 자동 업데이트 ▲ 배경색은 해당 항목에서 상대적으로 유리한 쪽을 표시합니다 — 비교는 일반적인 경향이며 실제 유·불리는 용도에 따라 다릅니다
LFS vs 일반 배포판 비교 — 7개 항목별 장단점 대조

LFS 버전 변천사

LFS는 1999년 첫 릴리스 이후 꾸준히 발전해왔습니다. 주요 이정표를 정리합니다.

시기버전주요 변화
1999LFS 1.0Gerard Beekmans가 프로젝트 시작, 최초의 "소스에서 빌드" 가이드
2002LFS 4.0패키지 수 40개 이상, 안정적 빌드 절차 확립
2004LFS 6.0Udev 도입, 2.6 커널 기반, 빌드 절차 대폭 개선 (2004년 릴리스)
2007LFS 6.3보안 수정 중심 (Linux-2.6.22.5, GCC-4.1.2, Glibc-2.5). 임시 도구는 여전히 네이티브 빌드
2011LFS 7.02011년 릴리스. 크로스 컴파일 방식 도입 (LFS_TGT 기반 크로스 툴체인), /run tmpfs, md5sums 파일 추가
2015-03LFS 7.7SysV 계열 안정화 릴리스
2016-03LFS 7.9systemd 에디션이 'Stable Systemd'로 처음 공식 안정 릴리스
2019LFS 9.0Python 3 필수화, Meson/Ninja 도입, GCC 9 기반
2021LFS 11.0/usr 병합 완료 (/bin→/usr/bin, /lib→/usr/lib 심볼릭 링크)
2023LFS 12.0pkgconf 도입(pkg-config 대체), GCC 13 기반, Glibc 2.38
2024-03LFS 12.1Glibc 2.39, 커널 6.7.4 기반 안정화 릴리스
2024-09LFS 12.2GCC 14.2, Glibc 2.40, 커널 6.10, systemd 256
2025-03LFS 12.3Binutils 2.44, Glibc 2.41, 커널 6.13.2, 45개 패키지 갱신
2025-09LFS 12.4Binutils 2.45, GCC 15.2.0, Glibc 2.42, 커널 6.16.1, systemd 257.8
2026-03LFS 13.0Binutils 2.46, Glibc 2.43, 커널 6.18.10, 보안 업데이트 중심 (expat/openssl/Python/vim/zlib)
2026-09LFS 13.1Binutils 2.47, GCC 16.2.0, Glibc 2.44, 커널 7.1.8, systemd 261.2 (46개 패키지 갱신)
LFS 주요 버전 타임라인 — 1999년 시작부터 2026년 LFS 13.1까지의 주요 이정표 LFS 주요 버전 타임라인 (1999~2026) 1999년 LFS 1.0부터 2026년 LFS 13.1까지의 주요 이정표 1.0 1999 프로젝트 시작 6.0 2004 Udev 7.0 2011 Systemd 분리 9.0 2019 Python 3 11.0 2021 /usr 병합 12.2 2024 GCC 14 12.4 2025-09 GCC 15.2 13.0 2026-03 Glibc 2.43 13.1 2026-09 Glibc 2.44 초기 확립기 현대화 (Systemd·크로스 컴파일) /usr 병합 시대 보안·ABI 안정화 (2025~)
LFS 주요 버전 타임라인 — 1999년 시작부터 2026년 LFS 13.0까지의 주요 이정표

LFS 기반 배포판

LFS 원칙을 기반으로 발전한 실제 배포판들이 있습니다. 이들은 LFS의 "소스에서 빌드" 철학을 자동화하거나 확장합니다.

배포판특징LFS와의 관계
Gentoo LinuxPortage 패키지 매니저, USE 플래그 기반 커스터마이징LFS 철학을 자동화, emerge로 소스 빌드
Arch LinuxPacman 패키지 매니저, 롤링 릴리스, KISS 원칙LFS와 유사한 미니멀 철학, 바이너리 패키지
CRUXports 기반 소스 빌드, 경량 시스템LFS 영향받은 소스 기반 배포판
NuTyXCards 패키지 매니저, LFS/BLFS 기반LFS를 직접 기반으로 한 배포판
Void LinuxXBPS 패키지 매니저, 독자적 빌드 시스템, runit init처음부터 독자 구축, LFS 정신 계승
Kiss Linux극도의 미니멀리즘, 셸 스크립트 패키지 매니저LFS보다 더 극단적인 미니멀 접근
LFS 빌드 완료 후의 $LFS 루트 디렉토리 트리 — /usr 병합(FHS 3.0) 레이아웃 $LFS 디렉토리 트리 구조 (빌드 완료 후) FHS 호환 레이아웃 — /usr 병합 이후 (LFS 11.0+) / ($LFS) /boot vmlinuz, config System.map, grub/ /usr /usr/bin gcc, bash, ls grep, sed, make... /usr/lib libc.so, libm.so libgcc_s.so... /usr/include linux/, asm/ stdio.h, stdlib.h /usr/share man/, info/ locale/, zoneinfo /etc passwd, group, hostname fstab, locale.conf, systemd/ /var log/, cache/ tmp/, run→/run /sources *.tar.xz (소스) *.patch (패치) /tools Pass 1 크로스 컴파일러 설치 위치 /dev /proc /sys 가상 FS (바인드 마운트) /usr 병합 (Usr-Merge) 심볼릭 링크 /bin → /usr/bin /sbin → /usr/sbin /lib → /usr/lib /lib64 → /usr/lib LFS 11.0+에서 /usr 병합 완료 — 모든 바이너리와 라이브러리는 /usr 아래에 설치 빌드 단계별 디렉토리 용도 /tools — Ch.5 크로스 컴파일러 (Pass 1). 빌드 완료 후 삭제 가능 /sources — 소스 타르볼 저장소. 빌드 완료 후 삭제하여 디스크 절약
$LFS 디렉토리 트리 구조 — /usr 병합 이후의 FHS 호환 레이아웃

가상머신 실습 환경 구성

LFS를 안전하게 실습하려면 가상머신(VM)을 사용하는 것이 좋습니다. 호스트 시스템에 영향을 주지 않고, 스냅샷으로 단계별 백업이 가능합니다.

도구추천 설정장점
VirtualBoxRAM 8GB+, 디스크 50GB (동적 할당), Ubuntu/Debian 호스트무료, 스냅샷, 공유 폴더
QEMU/KVMRAM 8GB+, virtio 디스크 50GB, virt-manager GUI고성능, 리눅스 네이티브, 자유도 높음
VMware WorkstationRAM 8GB+, 디스크 50GB, 스냅샷 활용안정성, 스냅샷 관리 편리
WSL2 (Windows)Ubuntu 24.04 WSL2, wsl --set-versionWindows 환경에서 LFS 학습 (제한적)
스냅샷 전략: 다음 시점에 스냅샷을 생성하면 실수 시 빠르게 복구할 수 있습니다.
  • 스냅샷 1: 호스트 준비 완료, $LFS 파티션 마운트 후
  • 스냅샷 2: Pass 1 크로스 툴체인 빌드 완료 후
  • 스냅샷 3: Chapter 6 임시 도구 빌드 완료 후
  • 스냅샷 4: Chroot 진입 직전 (가상 FS 마운트 전)
  • 스냅샷 5: Chapter 8 시스템 소프트웨어 빌드 완료 후
WSL2 제한사항: WSL2에서는 별도 파티션 생성과 GRUB 설치가 불가능합니다. Chroot 환경까지의 학습에는 적합하지만, 부팅 가능 시스템 완성에는 실제 VM이 필요합니다. 또한 WSL2에서는 /dev/loop 디바이스를 사용한 파일 기반 파티션으로 대체할 수 있습니다.

호스트 시스템 요구사항

LFS를 빌드하려면 호스트 시스템에 특정 버전 이상의 소프트웨어가 설치되어 있어야 합니다. 호스트는 LFS 빌드를 수행하는 기존 리눅스 시스템으로, 대부분의 최신 배포판(Ubuntu 24.04+, Fedora 41+, Debian 12+)이 요구사항을 충족합니다.

필수 패키지 및 최소 버전

패키지최소 버전확인 명령용도
Bash3.2+bash --version셸 스크립트 실행
Binutils2.13.1+ld --version어셈블러, 링커(Linker)
Bison2.7+bison --version파서 생성기
Coreutils8.1+chown --version기본 유틸리티
Diffutils2.8.1+diff --version파일 비교
Findutils4.2.31+find --version파일 검색
Gawk4.0.1+gawk --version텍스트 처리
GCC (C, C++)5.4+gcc --versionC/C++ 컴파일러
Glibc2.11+ldd --versionC 라이브러리
Grep2.5.1a+grep --version패턴 검색
Gzip1.3.12+gzip --version압축
Linux Kernel5.4+uname -r호스트 커널
M41.4.10+m4 --version매크로(Macro) 프로세서
Make4.0+make --version빌드 자동화
Patch2.5.4+patch --version패치 적용
Perl5.8.8+perl -V:version스크립트 언어
Python 33.4+python3 --version스크립트, 빌드 도구
Sed4.1.5+sed --version스트림 편집기
Tar1.22+tar --version아카이브
Texinfo5.0+makeinfo --version문서 도구
Xz Utils5.0.0+xz --version압축
/bin/sh 심볼릭 링크: /bin/sh가 반드시 bash를 가리켜야 합니다. Debian/Ubuntu에서는 기본값이 dash이므로 sudo ln -sf /bin/bash /bin/sh로 변경해야 합니다. LFS 빌드 스크립트들은 bash 전용 문법을 사용합니다.
13.0 하드웨어 권장 사양: LFS 13.0 공식 문서는 최소 4코어 CPU와 8GB RAM을 권장합니다. 이보다 낮은 사양에서도 빌드는 가능하지만, 시간이 크게 늘어납니다. 또한 호스트 컴파일러는 Binutils 2.46.0 / GCC 15.2.0보다 높은 버전은 권장되지 않습니다 (더 새로운 컴파일러가 툴체인 빌드를 깨뜨리는 사례가 보고된 적 있습니다).

version-check.sh 스크립트

아래 스크립트로 호스트 시스템의 요구사항을 한 번에 확인할 수 있습니다:

#!/bin/bash
# LFS 13.0 호스트 요구사항 검증 스크립트 (축약판)

export LC_ALL=C

# Bash 버전 확인
bash --version | head -n1 | cut -d" " -f2-4

# /bin/sh → bash 확인
MYSH=$(readlink -f /bin/sh)
echo "/bin/sh -> $MYSH"
echo -n "MYSH의 경로: "; echo $MYSH | grep -q bash || echo "ERROR: /bin/sh does not point to bash"
unset MYSH

echo -n "Binutils: "; ld --version | head -n1 | cut -d" " -f3-
bison --version | head -n1

if [ -h /usr/bin/yacc ]; then
  echo "/usr/bin/yacc -> $(readlink -f /usr/bin/yacc)"
elif [ -x /usr/bin/yacc ]; then
  echo yacc is $(/usr/bin/yacc --version | head -n1)
else
  echo "yacc not found"
fi

echo -n "Coreutils: "; chown --version | head -n1 | cut -d")" -f2
diff --version | head -n1
find --version | head -n1
gawk --version | head -n1

if [ -h /usr/bin/awk ]; then
  echo "/usr/bin/awk -> $(readlink -f /usr/bin/awk)"
elif [ -x /usr/bin/awk ]; then
  echo awk is $(/usr/bin/awk --version | head -n1)
else
  echo "awk not found"
fi

gcc --version | head -n1
g++ --version | head -n1
echo -n "Glibc: "; ldd --version | head -n1 | cut -d" " -f2-
grep --version | head -n1
gzip --version | head -n1
echo -n "Linux Kernel: "; cat /proc/version
m4 --version | head -n1
make --version | head -n1
patch --version | head -n1
echo -n "Perl: "; perl -V:version
python3 --version
sed --version | head -n1
tar --version | head -n1
makeinfo --version | head -n1  # texinfo
xz --version | head -n1

echo 'int main(){}' | g++ -x c++ -
if [ -x a.out ]; then
  echo "g++ compilation OK"
else
  echo "g++ compilation FAILED"
fi
rm -f a.out
Ubuntu/Debian 필수 패키지 설치:
sudo apt-get install build-essential bison gawk texinfo python3
Fedora/RHEL 필수 패키지 설치:
sudo dnf install gcc gcc-c++ make bison gawk texinfo python3 perl diffutils findutils patch

파티션 및 파일시스템(Filesystem) 준비

LFS 시스템을 위한 전용 파티션을 생성하고 파일시스템을 포맷합니다. 호스트 시스템과 별도의 파티션(또는 디스크)을 사용하는 것이 안전합니다.

추천 파티션 구성

마운트 포인트파일시스템최소 크기권장 크기설명
/ (루트)ext410 GB30 GBLFS 시스템 전체 (소스 + 빌드)
/bootext2200 MB500 MB커널, GRUB (선택)
swapswapRAM과 동일RAM × 2스왑 영역(Swap Area)
/homeext4-여유분사용자 데이터 (선택)

파티션 생성 및 포맷

# 디스크 확인 (예: /dev/sdb)
lsblk

# 파티션 생성 (fdisk 사용)
sudo fdisk /dev/sdb
# n → 새 파티션 → p (primary) → 크기 지정
# t → 파티션 타입 (82=swap, 83=Linux)
# w → 저장

# 또는 parted 사용 (GPT 테이블)
sudo parted /dev/sdb
# mklabel gpt
# mkpart primary ext4 1MiB 30GiB
# mkpart primary linux-swap 30GiB 34GiB
# quit

# 파일시스템 포맷
sudo mkfs -v -t ext4 /dev/sdb1

# 스왑 포맷
sudo mkswap /dev/sdb2

$LFS 변수 설정 및 마운트

# LFS 환경 변수 설정 (반드시 설정!)
export LFS=/mnt/lfs

# 마운트 포인트 생성 및 마운트
sudo mkdir -pv $LFS
sudo mount -v -t ext4 /dev/sdb1 $LFS

# 스왑 활성화
sudo swapon /dev/sdb2

# 소스 디렉토리 생성
sudo mkdir -v $LFS/sources
sudo chmod -v a+wt $LFS/sources
별도 /home 파티션: /home을 별도 파티션으로 분리하면 LFS를 재빌드할 때 사용자 데이터를 보존할 수 있습니다. 또한 여러 LFS 빌드에서 같은 /home을 공유할 수 있습니다.
호스트 재부팅 시 주의: 재부팅하면 $LFS 변수가 초기화되고 마운트가 해제됩니다. 작업을 재개하기 전에 반드시 export LFS=/mnt/lfs와 mount 명령을 다시 실행하세요. /etc/fstab에 추가하면 자동 마운트됩니다.

환경 변수 설정

LFS 빌드를 위한 전용 사용자(lfs)를 생성하고, 깨끗한 환경을 구성합니다. 호스트의 환경 변수가 빌드에 영향을 주지 않도록 격리하는 것이 핵심입니다.

lfs 사용자 생성

# lfs 그룹 및 사용자 생성
sudo groupadd lfs
sudo useradd -s /bin/bash -g lfs -m -k /dev/null lfs

# 비밀번호 설정
sudo passwd lfs

# $LFS 디렉토리 소유권 변경
sudo chown -v lfs $LFS/{usr{,/*},lib,var,etc,bin,sbin,tools}
case $(uname -m) in
  x86_64) sudo chown -v lfs $LFS/lib64 ;;
esac

# lfs 사용자로 전환
su - lfs

환경 변수 참조표

변수값설명
LFS/mnt/lfsLFS 시스템 마운트 포인트
LC_ALLPOSIX로케일을 POSIX로 고정하여 빌드 재현성 확보
LFS_TGTx86_64-lfs-linux-gnu크로스 컴파일러 타겟 트리플렛
PATH$LFS/tools/bin:/usr/bin크로스 컴파일러를 우선 탐색
CONFIG_SITE$LFS/usr/share/config.siteconfigure 스크립트 기본값 오버라이드
MAKEFLAGS-j$(nproc)병렬 빌드 (CPU 코어 수만큼)

.bash_profile

exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash

exec env -i는 기존 환경 변수를 모두 제거하고 깨끗한 셸을 시작합니다. HOME, TERM, PS1만 유지합니다.

.bashrc

set +h          # 해시 비활성화 (PATH 변경을 즉시 반영)
umask 022       # 파일 권한 기본값
LFS=/mnt/lfs
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/usr/bin
if [ ! -L /bin ]; then PATH=/bin:$PATH; fi
PATH=$LFS/tools/bin:$PATH
CONFIG_SITE=$LFS/usr/share/config.site
MAKEFLAGS="-j$(nproc)"
export LFS LC_ALL LFS_TGT PATH CONFIG_SITE MAKEFLAGS
LC_ALL=POSIX의 중요성: 이 설정 없이는 빌드 중 로케일 관련 오류가 발생할 수 있습니다. 예를 들어, 터키어 로케일에서 toupper('i')가 'I' 대신 'İ'를 반환하여 configure 스크립트가 실패합니다. POSIX(= C) 로케일은 ASCII 기반 동작을 보장합니다.

CONFIG_SITE 파일

# $LFS/usr/share/config.site
# configure 스크립트가 자동으로 읽는 설정 파일

# Autoconf 캐시 변수: 크로스 컴파일 시 테스트 불가능한 값을 사전 지정
ac_cv_func_mmap_fixed_mapped=yes
ac_cv_func_working_mktime=yes
set +h (해시(Hash) 비활성화): Bash는 실행 파일 경로를 해시 테이블(Hash Table)에 캐시(Cache)합니다. set +h로 이를 비활성화하면, 새로 빌드한 도구가 $PATH에 설치되었을 때 즉시 사용됩니다. 해시가 활성화되어 있으면 이전 경로가 캐시되어 오래된 도구가 사용될 수 있습니다.

크로스 컴파일 기초 이론

크로스 컴파일(cross-compilation)은 현재 실행 중인 시스템(빌드 머신)과 다른 환경에서 실행될 프로그램을 컴파일하는 기술입니다. LFS에서 크로스 컴파일은 단순히 다른 아키텍처를 타겟으로 하는 것이 아니라, 호스트 시스템의 라이브러리 오염을 완전히 차단하기 위한 핵심 전략입니다.

Build / Host / Target 개념

GNU 빌드 시스템에서 사용하는 세 가지 머신 개념을 정확히 이해해야 합니다:

용어의미LFS에서의 역할
Build 컴파일러를 실행하는 머신 (컴파일이 수행되는 곳) 호스트 시스템 (예: x86_64-pc-linux-gnu)
Host 컴파일된 프로그램이 실행될 머신 LFS 시스템 (예: x86_64-lfs-linux-gnu)
Target 컴파일된 프로그램이 생성하는 코드가 실행될 머신 (컴파일러에만 해당) 컴파일러 빌드 시에만 사용 (x86_64-lfs-linux-gnu)
Target은 컴파일러에만 의미가 있습니다. 일반 프로그램(bash, coreutils 등)은 --build와 --host만 사용합니다. --target은 GCC나 Binutils처럼 다른 코드를 생성하는 도구에만 의미가 있습니다.

LFS 크로스 컴파일 단계별 Build/Host/Target 값

단계빌드 대상--build--host--target설명
Pass 1 Binutils x86_64-pc-linux-gnu (= build) $LFS_TGT 호스트에서 실행, LFS용 코드 생성
Pass 1 GCC x86_64-pc-linux-gnu (= build) $LFS_TGT 호스트에서 실행, LFS용 코드 생성
- Glibc ../config.guess $LFS_TGT - 크로스 컴파일러로 빌드, LFS에서 실행
Ch.6 임시 도구 $(build-aux/config.guess) $LFS_TGT - 크로스 컴파일러로 빌드, LFS에서 실행
Pass 2 Binutils $(../config.guess) $LFS_TGT - 크로스 컴파일, LFS에서 네이티브로 실행
Pass 2 GCC $(../config.guess) $LFS_TGT $LFS_TGT LFS에서 실행, LFS용 코드 생성 (네이티브)
Build/Host/Target 트리플렛 관계 — Build에서 컴파일, Host에서 실행, Target은 컴파일러가 생성하는 코드의 실행 환경 Build / Host / Target 트리플렛 관계 Build Machine x86_64-pc-linux-gnu 컴파일을 수행하는 머신 • configure · make 실행 • 호스트 GCC · binutils 사용 • pass 1 툴체인 생성 • 결과물: 크로스 GCC Host Machine x86_64-lfs-linux-gnu 빌드된 프로그램이 실행될 머신 • $LFS 파티션 = 미래 시스템 • 빌드 결과물 실행 위치 • 크로스 GCC 실행 위치 • 툴 · 라이브러리 설치 대상 Target Machine x86_64-lfs-linux-gnu 생성된 코드가 실행될 머신 • 컴파일러에만 해당 • GCC · Binutils 빌드 시 사용 • 코드 생성 대상 지정 • 최종 LFS 시스템 툴체인 실행 코드 생성 Build ≠ Host = Target — x86_64-pc-linux-gnu → x86_64-lfs-linux-gnu 같은 CPU 아키텍처(x86_64)지만 vendor를 ‘lfs’로 바꿔 호스트 라이브러리 오염을 차단합니다
Build/Host/Target 세 머신의 관계 — Build에서 컴파일, Host에서 실행, Target은 컴파일러가 생성하는 코드의 실행 환경

왜 같은 아키텍처에서 크로스 컴파일을 하는가?

LFS에서 빌드 머신과 타겟 머신의 CPU 아키텍처가 같은데도(둘 다 x86_64) 크로스 컴파일을 하는 이유는 호스트 라이브러리 오염 방지입니다:

호스트 라이브러리 오염: 빌드된 LFS 프로그램이 호스트의 /usr/lib/libc.so에 링크되면, LFS 시스템을 독립적으로 부팅할 수 없습니다. 크로스 컴파일은 이 오염을 원천적으로 차단합니다. 트리플렛이 다르면 컴파일러가 호스트의 라이브러리 경로를 절대 참조하지 않기 때문입니다.
컴파일 유형 비교 — Native / Cross / Canadian Cross와 LFS의 의사 크로스 컴파일 전략 컴파일 유형 비교: Native vs Cross vs Canadian Cross Native Compile A A A Build = Host = Target A에서 빌드, A에서 실행, A용 코드 생성 Cross Compile A A B Build = Host ≠ Target A에서 빌드·실행, B용 코드 생성 Canadian Cross A B C Build ≠ Host ≠ Target A에서 빌드, B에서 실행, C용 코드 생성 LFS의 전략: "의사 크로스 컴파일" Build: x86_64-pc-linux-gnu Host=Target: x86_64-lfs-linux-gnu 같은 CPU 아키텍처이지만 트리플렛의 vendor를 'lfs'로 변경하여 호스트와 분리
컴파일 유형 비교 — LFS는 같은 아키텍처에서도 크로스 컴파일 전략을 사용

트리플렛(Triplet) 형식

GNU 트리플렛은 시스템을 식별하는 문자열로, arch-vendor-kernel-os 형태입니다:

# 호스트 시스템 트리플렛 확인
gcc -dumpmachine
# 출력 예: x86_64-pc-linux-gnu 또는 x86_64-linux-gnu

# LFS 타겟 트리플렛
echo $LFS_TGT
# 출력: x86_64-lfs-linux-gnu
필드호스트LFS 타겟설명
archx86_64x86_64CPU 아키텍처 (동일)
vendorpclfs벤더 (의도적으로 다르게 설정)
kernellinuxlinux커널 (동일)
osgnugnuOS/ABI (동일)

Bootstrap 문제와 Pass 개념

Bootstrap 문제(Bootstrap Problem)는 "닭이 먼저냐, 달걀이 먼저냐"와 같은 순환 의존성 딜레마입니다. GCC를 빌드하려면 C 표준 라이브러리(glibc)의 헤더가 필요하고, glibc를 빌드하려면 GCC 컴파일러가 이미 있어야 합니다. 이 순환을 깨기 위해 LFS는 다단계 패스(Multi-Pass) 전략을 사용합니다.

일상 비유: 첫 번째 집을 지을 때 간단한 임시 도구로 기초를 세우고, 그 기초 위에서 더 좋은 도구를 만든 뒤, 마침내 완성된 도구로 집을 완공하는 것과 같습니다. LFS에서 "임시 도구 = Pass 1 크로스 컴파일러", "완성된 도구 = Pass 2 네이티브 컴파일러"입니다.

Pass 1 vs Pass 2 핵심 차이

구분Pass 1 (임시 크로스 도구)Pass 2 (최종 네이티브 도구)
Binutils크로스 어셈블러·링커 — $LFS/tools/bin에 설치LFS 자체용 — $LFS/usr/bin에 설치
GCCC 컴파일러만 (C++ 없음, 최소 기능, 내부 정적 libc 사용)C + C++ 완전 지원, 최적화 옵션 모두 활성화
GlibcPass 1 GCC + 크로스 링커로 빌드 ($LFS/usr/lib)Pass 2 GCC로 재빌드 — 완전한 런타임 제공
Libstdc++GCC Pass 1 소스에서 최소 버전 빌드GCC Pass 2 소스에서 완전 버전 재빌드
목적호스트 오염 없이 최소 크로스 빌드 환경 구성LFS 파티션에서 자급자족하는 완전한 툴체인 구성

Bootstrap 해결 순서

  1. Binutils Pass 1: 호스트 GCC로 크로스 링커(x86_64-lfs-linux-gnu-ld)를 빌드합니다. GCC의 configure 스크립트가 이 링커를 감지·테스트하므로 반드시 먼저 빌드해야 합니다.
  2. GCC Pass 1: 호스트 GCC로 최소 크로스 컴파일러를 빌드합니다. C 언어만 지원하며, glibc 없이 내부 정적 libgcc를 사용합니다.
  3. Linux API 헤더: make headers_install로 커널 헤더를 $LFS/usr/include에 복사합니다. 이 헤더가 있어야 glibc를 빌드할 수 있습니다.
  4. Glibc: GCC Pass 1 크로스 컴파일러로 빌드합니다. 이제 C 표준 라이브러리(libc.so)가 $LFS/usr/lib에 존재합니다.
  5. Libstdc++ Pass 1: GCC Pass 1으로 C++ 표준 라이브러리 최소 버전을 빌드합니다. 이후 임시 도구 크로스 컴파일 단계에서 C++ 코드를 빌드하기 위해 필요합니다.

이 다섯 단계가 끝나면 $LFS 파티션은 자체 크로스 컴파일러와 Glibc를 갖춥니다. 이후 임시 도구 빌드와 Chroot 진입을 거쳐 Pass 2 컴파일러를 빌드하면 Bootstrap이 완료됩니다.

툴체인 기술 분석

툴체인(toolchain)은 소스 코드를 실행 가능한 바이너리로 변환하는 도구 집합입니다. LFS 크로스 툴체인은 Binutils, GCC, Glibc, Libstdc++로 구성되며, 각 구성요소가 정밀하게 맞물려 동작합니다.

툴체인 구성요소

구성요소주요 도구역할빌드 순서
Binutilsas, ld, ar, objdump어셈블러, 링커, 아카이버1번째 (Pass 1)
GCCcc1, cc1plus, collect2C/C++ 컴파일러 (전처리→컴파일→어셈블)2번째 (Pass 1)
Linux Headers헤더 파일만커널-사용자공간 인터페이스 정의3번째
Glibclibc.so, ld-linux.so, crt*.oC 표준 라이브러리, 동적 링커4번째
Libstdc++libstdc++.soC++ 표준 라이브러리5번째
크로스 컴파일 파이프라인 — 소스(.c)부터 ELF 바이너리까지 6단계, 모든 도구가 $LFS_TGT- 접두사를 사용 크로스 컴파일 파이프라인 모든 도구가 $LFS_TGT- 접두사로 실행 — 전처리(cpp)는 헤더를, 링크(ld)는 라이브러리를 Sysroot에서 참조 소스 (.c) 원시 코드 전처리 (cpp) $LFS_TGT-cpp 컴파일 (cc1) $LFS_TGT-gcc 어셈블 (as) $LFS_TGT-as 링크 (ld) $LFS_TGT-ld 바이너리 (ELF) LFS에서 실행 가능 헤더 라이브러리 Sysroot ($LFS): 헤더 + 라이브러리 참조 $LFS/usr/include (헤더) + $LFS/usr/lib (라이브러리)
크로스 컴파일 파이프라인(Pipeline) — 모든 도구가 $LFS_TGT- 접두사를 사용하며 Sysroot에서 헤더/라이브러리를 참조
툴체인 의존성 순환 해결 — GCC↔Glibc가 서로를 필요로 하는 고리를 GCC Pass 1(--with-newlib)에서 절단해 선형 빌드 순서로 펼침 의존성 순환 문제와 해결 GCC ↔ Glibc가 서로를 필요로 하는 고리 — Pass 1(--with-newlib)에서 절단해 선형 순서로 펼칩니다 GCC (libgcc 필요) Glibc (헤더/라이브러리) glibc 필요 libgcc 필요 ! 절단 → 선형 순서 1. GCC Pass 1 glibc 없이 제한 빌드 2. Linux Headers 시스템 콜 번호 정의 3. Glibc libgcc로 순환 차단! 4. Libstdc++ libc.so 링크로 완성 --with-newlib --without-headers libgcc_eh → libgcc_s (inhibit_libc 우회) 같은 컴포넌트 — 절단 후에는 무한 루프가 없는 선형 순서만 남습니다
GCC↔Glibc 의존성 순환 — GCC Pass 1에서 --with-newlib로 glibc 없이 제한적 빌드 후, Glibc를 빌드하여 순환을 끊음
의존성 순환이 해결되지 않으면 빌드 불가! GCC는 C 런타임 시작 코드(crt1.o, crti.o)를 Glibc에서 가져오고, Glibc는 내부 예외 처리를 위해 libgcc_s.so가 필요합니다. 이 "닭과 달걀" 문제를 해결하는 유일한 방법은 Pass 1에서 --with-newlib(glibc 불필요 모드)로 최소 GCC를 빌드한 뒤, 이 GCC로 Glibc를 컴파일하는 것입니다.
Sysroot 디렉토리 구조 — tools/에는 호스트에서 실행되는 크로스 도구, usr/에는 타겟의 헤더·라이브러리 Sysroot ($LFS) 디렉토리 구조 tools/ = 호스트에서 실행되는 크로스 도구 | usr/ = 타겟의 헤더·라이브러리 (Sysroot) $LFS (/mnt/lfs) tools/ — 호스트에서 실행되는 크로스 도구 bin/ lib/ $LFS_TGT-gcc $LFS_TGT-ld libgcc.a libstdc++.a 호스트에서만 실행 — 타겟에는 복사되지 않음 usr/ — 타겟의 헤더·라이브러리 (Sysroot) include/ lib/ bin/ linux/ (커널 헤더) stdio.h (glibc) libc.so crt1.o bash ls, cat... chroot 후 타겟 시스템의 /usr로 사용됩니다 sources/ — 소스 타르볼 저장소, etc/ — 설정 파일 (호스트·타겟 구분 없음)
Sysroot 디렉토리 구조 — tools/에는 호스트에서 실행되는 크로스 도구, usr/에는 타겟의 헤더·라이브러리

Sysroot의 동작 원리

--with-sysroot=$LFS로 빌드된 크로스 컴파일러는 다음과 같이 라이브러리와 헤더를 탐색합니다:

# 크로스 컴파일러의 검색 경로 확인
$LFS_TGT-gcc -print-search-dirs

# 헤더 검색 경로 확인
$LFS_TGT-gcc -print-sysroot
# 출력: /mnt/lfs

# 실제 헤더 검색 순서
# 1. $LFS/usr/include
# 2. $LFS/tools/lib/gcc/$LFS_TGT/15.2.0/include
# 3. $LFS/tools/lib/gcc/$LFS_TGT/15.2.0/include-fixed

# 라이브러리 검색 순서
# 1. $LFS/usr/lib
# 2. $LFS/lib
# 3. $LFS/tools/lib
크로스 툴체인 빌드 순서 총정리 — 5단계 빌드와 의존성 관계, Sanity Check 시점 크로스 툴체인 빌드 순서 총정리 (Chapter 5) 호스트에서 5단계 크로스 빌드 → $LFS(타겟)에 헤더·라이브러리 설치 → Sanity Check로 검증 후 진행 1. Binutils Pass 1 as, ld 크로스 빌드 — $LFS_TGT- 접두사 도구 산출물 → $LFS/tools/bin/ (as, ld) — 호스트에서 실행 2. GCC Pass 1 --with-newlib (제한적) — glibc 없이 컴파일러 생성 산출물 → $LFS/tools/bin/ ($LFS_TGT-gcc) — 호스트에서 실행 의존성: ← 1단계의 as/ld를 사용 크로스 컴파일러가 어셈블·링크에 필수로 사용 3. Linux API 헤더 make headers — 헤더만 설치 (빌드 없음) 산출물 → $LFS/usr/include/ — 타겟용 시스템 콜 번호·구조체 4. Glibc libc.so, ld-linux.so, crt*.o — 순환 의존성 해결! 산출물 → $LFS/usr/ (lib, include) — 타겟용 C 라이브러리 의존성: ← 3단계 헤더의 syscall 번호 참조 GCC Pass 1로 크로스 빌드, 동적 링커 포함 ! 필수! Sanity Check — 통과한 뒤에만 5단계 진행 echo 'int main(){}' | $LFS_TGT-gcc -xc - readelf -l a.out | grep ld-linux → /lib64/ld-linux-x86-64.so.2 (실패 시 재검토) 5. Libstdc++ C++ 표준 라이브러리 — Glibc 위에 빌드 산출물 → $LFS/usr/lib/ (libstdc++.so) — 타겟용 C++ 라이브러리 의존성: ← 4단계 libc.so에 링크 Glibc 위에서 동작하는 C++ 표준 라이브러리 Chapter 6: 임시 도구 크로스 컴파일 m4, ncurses, bash, coreutils... → $LFS/usr/ 에 설치
크로스 툴체인 빌드 순서 총정리 — 5단계 빌드와 의존성 관계, Sanity Check 시점

Binutils Pass 1

Binutils는 어셈블러(as)와 링커(ld)를 포함하는 패키지로, 툴체인에서 가장 먼저 빌드합니다. GCC와 Glibc의 configure 스크립트가 as와 ld의 기능을 테스트하여 빌드 옵션을 결정하기 때문입니다.

왜 Binutils가 먼저인가? GCC의 configure는 링커(ld)가 지원하는 기능(예: --hash-style=gnu)을 테스트합니다. Binutils가 없으면 GCC configure가 기능 감지에 실패하여 최적화되지 않은 설정이 적용됩니다.
패키지 빌드 4단계 패턴 (Autotools 빌드 사이클): LFS의 모든 패키지는 동일한 4단계 패턴으로 빌드됩니다. 이 패턴을 이해하면 어떤 패키지든 자신 있게 빌드할 수 있습니다.
  1. 압축 해제 (tar): tar -xf 패키지.tar.xz — 소스 아카이브를 소스 트리로 추출합니다.
  2. 구성 (configure): ./configure --prefix=... — 빌드 환경을 탐지하고 Makefile을 생성합니다. --prefix는 바이너리가 설치될 기본 경로이고, --with-sysroot 등은 크로스 빌드 경로를 지정합니다.
  3. 빌드 (make): make — 소스를 컴파일하고 링크하여 실행 파일과 라이브러리를 생성합니다. make -j$(nproc)으로 병렬 빌드하면 빌드 시간을 단축할 수 있습니다.
  4. 설치 (make install): make install — 빌드된 바이너리·헤더·라이브러리를 prefix 경로에 복사합니다.

별도 빌드 디렉토리(mkdir build && cd build)를 만들고 ../configure를 실행하는 이유는 소스 트리를 오염시키지 않고, 재빌드 시 rm -rf build로 깨끗하게 초기화하기 위해서입니다. GCC와 Binutils는 소스 트리에서 직접 configure를 실행하면 빌드에 실패하므로 이 방식이 필수적입니다.

빌드 절차

# 소스 압축 해제 및 빌드 디렉토리 생성
cd $LFS/sources
tar -xf binutils-2.46.0.tar.xz
cd binutils-2.46.0
mkdir -v build
cd build

# configure
../configure                  \
    --prefix=$LFS/tools       \
    --with-sysroot=$LFS       \
    --target=$LFS_TGT         \
    --disable-nls             \
    --enable-gprofng=no       \
    --disable-werror          \
    --enable-new-dtags        \
    --enable-default-hash-style=gnu

# 빌드 및 설치
make
make install

configure 옵션 상세

옵션설명
--prefix=$LFS/tools크로스 도구를 $LFS/tools/bin에 설치. 호스트의 /usr/bin과 분리
--with-sysroot=$LFS링커가 $LFS를 sysroot로 사용하여 타겟 라이브러리를 여기서 탐색
--target=$LFS_TGTx86_64-lfs-linux-gnu를 타겟으로 설정. 호스트와 다른 트리플렛이므로 크로스 도구 생성
--disable-nls다국어 지원(Native Language Support) 비활성화. 임시 도구에는 불필요하며 빌드 시간 단축
--enable-gprofng=nogprofng 프로파일링(Profiling) 도구 비활성화. 크로스 빌드 시 불필요
--disable-werror경고를 오류로 처리하지 않음. 호스트 컴파일러 버전에 따른 경고로 빌드 실패 방지
--enable-new-dtags새로운 DT_RUNPATH 태그 사용 (DT_RPATH 대신). 보안 및 호환성 향상
--enable-default-hash-style=gnuGNU 해시 스타일을 기본값으로 설정. 심볼 조회 성능 향상

GCC Pass 1

GCC Pass 1은 최소한의 크로스 컴파일러를 빌드합니다. Glibc가 아직 없으므로 --with-newlib과 --without-headers를 사용하여 C 라이브러리 없이도 동작하는 제한적 GCC를 만듭니다.

--with-newlib의 의미: 이 옵션은 "newlib를 실제로 사용합니다"는 뜻이 아닙니다. GCC 내부적으로 inhibit_libc를 정의하여 glibc 헤더 없이 빌드할 수 있게 하는 플래그입니다. 이름이 혼동을 주지만, 실제로 newlib 라이브러리를 설치하거나 사용하지는 않습니다.

사전 준비: MPFR, GMP, MPC 추출

cd $LFS/sources
tar -xf gcc-15.2.0.tar.xz
cd gcc-15.2.0

# GCC가 의존하는 다중 정밀도 수학 라이브러리 압축 해제
tar -xf ../mpfr-4.2.2.tar.xz
mv -v mpfr-4.2.2 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에서 라이브러리 디렉토리를 lib64가 아닌 lib으로 설정
case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
  ;;
esac

빌드 절차

mkdir -v build
cd build

../configure                             \
    --target=$LFS_TGT                    \
    --prefix=$LFS/tools                  \
    --with-glibc-version=2.43            \
    --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
make install

limits.h 헤더 생성

# GCC 내부 limits.h 생성 (시스템 limits.h를 포함하는 래퍼)
cd ..
cat gcc/limitx.h gcc/glimits.h gcc/limity.h > \
  `dirname $($LFS_TGT-gcc -print-libgcc-file-name)`/include/limits.h

configure 옵션 상세

옵션설명
--target=$LFS_TGTx86_64-lfs-linux-gnu용 코드를 생성하는 크로스 컴파일러
--prefix=$LFS/tools크로스 컴파일러를 $LFS/tools에 설치
--with-glibc-version=2.43타겟 glibc 버전을 지정 (호환성 헤더 생성용)
--with-sysroot=$LFSsysroot를 $LFS로 설정하여 타겟 헤더/라이브러리 경로 지정
--with-newlibinhibit_libc 정의 — glibc 없이 빌드 가능하게 함
--without-headers시스템 헤더 없이 빌드. 커널 헤더가 아직 없으므로 필수
--enable-default-piePosition-Independent Executable을 기본값으로. ASLR 보안 강화
--enable-default-sspStack Smashing Protector를 기본 활성화. 스택 버퍼 오버플로(Buffer Overflow) 방지
--disable-shared정적 라이브러리만 빌드. 크로스 컴파일 시 공유 라이브러리(Shared Library) 문제 방지
--disable-multilib32비트 지원 비활성화. x86_64 전용
--disable-threads스레드(Thread) 지원 비활성화. glibc의 pthread가 아직 없으므로
--disable-libatomiclibatomic 빌드 생략 (glibc 필요)
--disable-libgompOpenMP 라이브러리 생략 (pthread 필요)
--disable-libquadmath128비트 수학 라이브러리 생략
--disable-libsspSSP 라이브러리 생략 (glibc가 이를 제공)
--disable-libvtvVTV(Virtual Table Verification) 생략
--disable-libstdcxxC++ 표준 라이브러리 생략 (나중에 별도 빌드)
--enable-languages=c,c++C와 C++만 활성화. Fortran, Go 등 불필요한 프론트엔드 제외

Linux API 헤더

Linux 커널은 사용자 공간(User Space) 프로그램이 커널 서비스를 호출할 수 있도록 C 헤더 파일을 제공합니다. 이 헤더는 시스템 콜 번호, 구조체(Struct) 정의, ioctl 명령 등을 포함하며, Glibc가 빌드될 때 이 헤더를 참조합니다.

사용자 공간 API 헤더 vs 커널 내부 헤더: make headers로 추출되는 헤더는 사용자 공간 API 헤더만 포함합니다. 커널 내부 구현 헤더(kernel/, mm/ 등)는 제외됩니다. 추출된 헤더는 #define과 struct 정의만 포함하며, 컴파일된 코드는 없습니다.

빌드 절차

cd $LFS/sources
tar -xf linux-6.18.10.tar.xz
cd linux-6.18.10

# 이전 빌드 아티팩트 제거
make mrproper

# 사용자 공간 헤더 추출
make headers

# 헤더 설치 ($LFS/usr/include로 복사)
find usr/include -type f ! -name '*.h' -delete
cp -rv usr/include $LFS/usr

make headers는 커널 소스에서 __KERNEL__ 가드로 보호된 내부 전용 코드를 제거하고, 사용자 공간에서 사용 가능한 헤더만 추출합니다. 주요 디렉토리:

디렉토리내용
linux/시스템 콜 번호, ioctl, 소켓(Socket), 파일시스템 구조체 등
asm/아키텍처별 정의 (레지스터(Register), 시그널(Signal) 등)
asm-generic/아키텍처 공통 정의
drm/DRM/KMS 인터페이스
mtd/MTD(Memory Technology Device) 인터페이스
scsi/SCSI 인터페이스
sound/ALSA 인터페이스
video/비디오 인터페이스

Glibc 크로스 빌드

Glibc(GNU C Library)는 리눅스 시스템의 핵심 라이브러리입니다. printf, malloc, open 등 모든 C 표준 함수와 시스템 콜 래퍼, 동적 링커(ld-linux-x86-64.so.2), C 런타임 시작 코드(crt1.o)를 제공합니다.

Glibc 내부 구성요소 — 실행 흐름(좌)과 libc.so.6 내부 구성(우)의 관계 Glibc 내부 구성요소 사용자 프로그램이 커널과 소통하는 모든 인터페이스 사용자 프로그램 bash · ls · gcc · python3 · make — 모든 프로세스가 Glibc를 경유하여 커널 서비스를 이용 execve() GNU C Library (Glibc 2.43) 실행 순서 1 동적 링커/로더 — ld-linux-x86-64.so.2 ELF 해석 → libc.so.6 및 의존 .so 로드 심볼 해결(Symbol Resolution) — lazy binding으로 지연 2 C 런타임 시작 코드 — crt1.o · crti.o · crtn.o _start → __libc_start_main → main() 호출 .init/.fini — 생성자(Ctor)·소멸자(Dtor) 실행 3 C 표준 라이브러리 — libc.so.6 printf · malloc · open · pthread_create Glibc 2.34+에서 libpthread·libdl·librt 통합 시스템 콜 래퍼 → 커널 libc.so.6 내부 구성 핵심 라이브러리 표준 I/O printf · scanf · fopen · fclose 메모리 할당 malloc · free · realloc · mmap 래퍼 문자열/수학/정렬 strcpy · sin · cos · qsort 시스템 콜 래퍼 open · read · write + errno 부가 서비스 NSS Name Service Switch libnss_files · libnss_dns 로케일 데이터 locale-archive · charmap 날짜·시간·숫자 포맷 libresolv DNS 해석 /etc/resolv.conf iconv / gconv 문자 인코딩 변환 상세 libresolv · iconv · NSS · 로케일 모두 커널 시스템 콜을 경유합니다 추가 모듈: libnss_compat · libidn · gencat · localedef … 리눅스 커널 — 시스템 콜 인터페이스 sys_read · sys_write · sys_open · sys_mmap · sys_ioctl …
Glibc 내부 구성요소 — 실행 순서(좌측)와 libc.so.6 내부 구성(우측)의 관계, 모든 경로가 커널 시스템 콜로 수렴

사전 준비

cd $LFS/sources
tar -xf glibc-2.43.tar.xz
cd glibc-2.43

# LSB 호환성 심볼릭 링크 생성
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

# FHS 호환 패치 적용
patch -Np1 -i ../glibc-fhs-1.patch

빌드 절차

mkdir -v build
cd build

# 환경 변수 설정 (configure가 올바른 루트 경로를 사용하도록)
echo "rootsbindir=/usr/sbin" > configparms

../configure                             \
    --prefix=/usr                        \
    --host=$LFS_TGT                      \
    --build=$(../scripts/config.guess)   \
    --enable-kernel=5.4                 \
    --with-headers=$LFS/usr/include      \
    --disable-nscd                       \
    libc_cv_slibdir=/usr/lib

make
make DESTDIR=$LFS install

configure 옵션 상세

옵션설명
--prefix=/usr최종 시스템에서의 설치 경로. DESTDIR=$LFS와 결합하여 $LFS/usr에 설치
--host=$LFS_TGT크로스 컴파일 모드 활성화. $LFS_TGT-gcc를 사용하여 빌드
--build=$(../scripts/config.guess)호스트 시스템의 트리플렛을 자동 감지
--enable-kernel=5.4최소 커널 버전 지정. 5.4 이전 커널의 호환 코드를 제외하여 크기 축소. LFS 13.0 기준 최소 지원 커널
--with-headers=$LFS/usr/includeLinux API 헤더 위치. 이전 단계에서 설치한 헤더를 참조
--disable-nscdName Service Cache Daemon 비활성화 (LFS에서 불필요)
libc_cv_slibdir=/usr/lib공유 라이브러리를 /usr/lib에 설치 (/lib64 대신)

Sanity Check (필수!)

Sanity Check 실패 시 반드시 중단! 아래 테스트가 실패하면 이전 단계에서 문제가 있는 것입니다. Binutils, GCC, Linux 헤더 설치를 처음부터 다시 검토해야 합니다. 절대로 다음 단계로 진행하지 마세요.
# 간단한 프로그램을 크로스 컴파일하여 동적 링커 경로 확인
echo 'int main(){}' | $LFS_TGT-gcc -xc -
readelf -l a.out | grep ld-linux

# 기대 출력:
# [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

# 클린업
rm -v a.out

위 출력에서 /lib64/ld-linux-x86-64.so.2가 표시되어야 합니다. 다른 경로(예: 호스트의 /lib/ld-linux.so.2)가 나오면 크로스 컴파일러가 올바르게 구성되지 않은 것입니다.

limits.h 수정

# GCC 내부 limits.h를 수정하여 시스템 limits.h를 포함하도록
$LFS/tools/libexec/gcc/$LFS_TGT/15.2.0/install-tools/mkheaders

Libstdc++ 초기 빌드

Libstdc++는 C++ 표준 라이브러리로, GCC 소스 트리 안에 포함되어 있습니다. GCC Pass 1에서는 --disable-libstdcxx로 빌드하지 않았으므로, 별도로 빌드합니다. 이 시점에서는 Glibc가 설치되어 있으므로 정상적인 C++ 라이브러리 빌드가 가능합니다.

왜 GCC Pass 1과 분리하는가? Libstdc++는 Glibc에 의존합니다. Pass 1에서는 Glibc가 없었으므로 빌드할 수 없었습니다. 이제 Glibc가 설치되었으므로 C++ 표준 라이브러리를 빌드할 수 있습니다.

빌드 절차

# GCC 소스 디렉토리에서 (이전 빌드 디렉토리 삭제 후)
cd $LFS/sources/gcc-15.2.0
rm -rf build
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++/15.2.0

make
make DESTDIR=$LFS install

# libtool .la 파일 제거 (크로스 컴파일 시 문제를 일으킬 수 있음)
rm -v $LFS/usr/lib/lib{stdc++{,exp,fs},supc++}.la

configure 옵션 상세

옵션설명
--host=$LFS_TGT크로스 컴파일 모드. $LFS_TGT-g++로 빌드
--build=$(../config.guess)호스트 시스템 트리플렛 자동 감지
--prefix=/usr최종 설치 경로 (DESTDIR=$LFS와 결합)
--disable-multilib32비트 지원 비활성화
--disable-nls다국어 지원 비활성화
--disable-libstdcxx-pch사전 컴파일 헤더 비활성화. 빌드 시간 절약 (크로스 빌드에서 효과 적음)
--with-gxx-include-dir=...C++ 헤더 설치 경로를 tools 안으로 지정. Pass 2에서 재빌드할 때까지 임시 위치 사용

임시 도구 크로스 컴파일

크로스 툴체인이 완성되었으므로, 이제 기본 유틸리티들을 크로스 컴파일하여 $LFS에 설치합니다. 이 도구들은 Chroot 환경에서 최종 시스템을 빌드하는 데 사용됩니다. Chapter 6의 패키지들은 모두 --host=$LFS_TGT를 사용하여 크로스 컴파일됩니다.

올바른 --host=$LFS_TGT 사용이 핵심: --host를 지정하면 configure는 $LFS_TGT-gcc를 컴파일러로 사용합니다. 이를 빠뜨리면 호스트의 GCC가 사용되어 호스트 라이브러리에 링크되는 오염이 발생합니다.

Chapter 6 패키지 목록

#패키지버전설명특이사항
1M41.4.21매크로 프로세서표준 크로스 빌드
2Ncurses6.6터미널 라이브러리호스트용 tic 먼저 빌드
3Bash5.3셸Chroot에서 /bin/bash로 사용
4Coreutils9.10기본 유틸리티 (ls, cp, mv 등)표준 크로스 빌드
5Diffutils3.12파일 비교표준 크로스 빌드
6File5.46파일 타입 판별호스트용 file 먼저 빌드
7Findutils4.10.0파일 검색 (find, xargs)표준 크로스 빌드
8Gawk5.3.2텍스트 처리표준 크로스 빌드
9Grep3.12패턴 검색표준 크로스 빌드
10Gzip1.14압축표준 크로스 빌드
11Make4.4.1빌드 자동화표준 크로스 빌드
12Patch2.8패치 적용표준 크로스 빌드
13Sed4.9스트림 편집기표준 크로스 빌드
14Tar1.35아카이브표준 크로스 빌드
15Xz5.8.2압축표준 크로스 빌드

표준 크로스 빌드 패턴

# 대부분의 패키지가 이 패턴을 따릅니다
cd $LFS/sources
tar -xf <package>-<version>.tar.xz
cd <package>-<version>

./configure --prefix=/usr                   \
            --host=$LFS_TGT                 \
            --build=$(build-aux/config.guess)

make
make DESTDIR=$LFS install

M4 빌드 예시

cd $LFS/sources
tar -xf m4-1.4.21.tar.xz
cd m4-1.4.21

./configure --prefix=/usr   \
            --host=$LFS_TGT \
            --build=$(build-aux/config.guess)

make
make DESTDIR=$LFS install

Ncurses 빌드 (특수 처리)

Ncurses는 tic (터미널 정보 컴파일러)를 빌드 과정에서 실행해야 하므로, 호스트용 tic를 먼저 빌드합니다:

cd $LFS/sources
tar -xf ncurses-6.6.tar.gz
cd ncurses-6.6

# 1단계: 호스트용 tic 빌드 (빌드 머신에서 실행할 도구)
mkdir build-tic
pushd build-tic
  ../configure
  make -C include
  make -C progs tic
popd

# 2단계: 크로스 컴파일
./configure --prefix=/usr                \
            --host=$LFS_TGT              \
            --build=$(./config.guess)     \
            --mandir=/usr/share/man       \
            --with-manpage-format=normal  \
            --with-shared                 \
            --without-normal              \
            --with-cxx-shared             \
            --without-debug               \
            --without-ada                 \
            --disable-stripping           \
            --enable-widec

make
make DESTDIR=$LFS TIC_PATH=$(pwd)/build-tic/progs/tic install

# libncurses 호환 심볼릭 링크
ln -sv libncursesw.so $LFS/usr/lib/libncurses.so

# pkgconfig 파일 수정
sed -e 's/^#if.*XOPEN.*$/#if 1/' \
    -i $LFS/usr/include/curses.h
모든 임시 도구는 $LFS/usr에 설치됩니다. --prefix=/usr와 DESTDIR=$LFS의 조합으로 실제 경로는 $LFS/usr/bin, $LFS/usr/lib 등이 됩니다. Chroot 환경에서는 $LFS가 /가 되므로 자연스럽게 /usr/bin, /usr/lib에서 찾을 수 있습니다.

Binutils/GCC Pass 2

Pass 2에서는 Chroot 환경 안에서 실행될 네이티브 컴파일러를 크로스 컴파일합니다. Pass 1의 크로스 컴파일러는 호스트에서 실행되지만, Pass 2의 결과물은 LFS 시스템 안에서 실행됩니다.

Pass 1 vs Pass 2 — 실행 머신과 산출물 실행 머신의 관계가 다릅니다 Pass 1 vs Pass 2 같은 GCC·Binutils를 두 번 빌드 — 실행 머신과 산출물이 실행될 머신의 관계가 다릅니다 Pass 1 — 크로스 컴파일러 호스트 시스템에서 실행 실행 위치 — 호스트 (빌드 머신) $LFS_TGT-gcc — 크로스 컴파일러 호스트에서 실행되지만 LFS 타겟용 바이너리를 생성 설치: $LFS/tools/bin · 최소 기능 (--with-newlib) --disable-shared (공유 라이브러리 없음) · --disable-threads 산출물 — LFS 타겟용 바이너리 Glibc · 임시 도구 (GCC Pass 2 포함) 도구 이름: $LFS_TGT- 접두사 (gcc · ld) 역할: Glibc·임시 도구를 크로스 빌드 빌드 머신(호스트) ≠ 실행 머신(LFS) — 크로스 컴파일 Pass 2 — 네이티브 컴파일러 LFS 시스템 (Chroot)에서 실행 실행 위치 — LFS (빌드 = 타겟 머신) gcc — 네이티브 컴파일러 LFS 안에서 실행되고 LFS용 바이너리를 생성 설치: $LFS/usr/bin → chroot 후 /usr/bin --enable-shared (공유 라이브러리) · POSIX 스레드 산출물 — 최종 시스템 바이너리 bash · coreutils · make 등 Chapter 6~8 패키지 도구 이름: gcc, ld (접두사 없음) 역할: Chroot에서 최종 패키지 빌드 빌드 머신(LFS) = 실행 머신(LFS) — 네이티브 컴파일 Pass 2 빌드 Glibc 전달 빌드 순서 (시간축) 1. GCC Pass 1 (호스트 · 크로스) 2. Glibc (타겟용 크로스 빌드) 3. GCC Pass 2 (LFS · 네이티브) 4. 최종 시스템 (LFS에서 빌드)
Pass 1 vs Pass 2 — Pass 1은 호스트에서 실행되는 크로스 컴파일러, Pass 2는 LFS에서 실행되는 네이티브 컴파일러

Binutils Pass 2

cd $LFS/sources
tar -xf binutils-2.46.0.tar.xz
cd binutils-2.46.0

# sed로 오래된 libtool 수정 (필요 시)
sed '6009s/$add_dir//' -i ltmain.sh

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-new-dtags         \
    --enable-default-hash-style=gnu

make
make DESTDIR=$LFS install

# libtool .la 파일 제거
rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la}

Binutils Pass 2 configure 옵션

옵션설명
--prefix=/usr최종 시스템의 /usr에 설치 (DESTDIR=$LFS 경유)
--host=$LFS_TGT크로스 컴파일: 빌드는 호스트에서, 결과물은 LFS에서 실행
--enable-shared공유 라이브러리 빌드 (Pass 1과 다름)
--enable-64-bit-bfd64비트 BFD 라이브러리 활성화

GCC Pass 2

cd $LFS/sources
tar -xf gcc-15.2.0.tar.xz
cd gcc-15.2.0

# MPFR, GMP, MPC 추출
tar -xf ../mpfr-4.2.2.tar.xz && mv -v mpfr-4.2.2 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

# lib64 → lib 수정
case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
  ;;
esac

# libgcc에서 크로스 빌드 오버라이드 방지
sed '/thread_header =/s/@.*@/gthr-posix.h/' \
    -i libgcc/Makefile.in libstdc++-v3/include/Makefile.in

mkdir -v build
cd build

../configure                                     \
    --build=$(../config.guess)                   \
    --host=$LFS_TGT                              \
    --target=$LFS_TGT                            \
    LDFLAGS_FOR_TARGET=-L$PWD/$LFS_TGT/libgcc   \
    --prefix=/usr                                \
    --with-build-sysroot=$LFS                    \
    --enable-default-pie                         \
    --enable-default-ssp                         \
    --disable-nls                                \
    --disable-multilib                           \
    --disable-libatomic                          \
    --disable-libgomp                            \
    --disable-libquadmath                        \
    --disable-libsanitizer                       \
    --disable-libssp                             \
    --disable-libvtv                             \
    --enable-languages=c,c++

make
make DESTDIR=$LFS install

# cc → gcc 심볼릭 링크 생성
ln -sv gcc $LFS/usr/bin/cc

GCC Pass 2 configure 옵션

옵션설명
--host=$LFS_TGT결과물이 LFS에서 실행되도록 크로스 컴파일
--target=$LFS_TGT이 GCC가 생성하는 코드도 LFS용 (네이티브 컴파일러)
LDFLAGS_FOR_TARGET=...타겟 라이브러리 빌드 시 libgcc 경로 지정
--with-build-sysroot=$LFS빌드 시 sysroot로 $LFS 사용
--disable-libsanitizerAddressSanitizer 등 비활성화 (크로스 빌드 시 문제)
Pass 2의 의미: Pass 2 이후 LFS에는 완전한 네이티브 컴파일러가 설치됩니다. Chroot 환경에 진입하면 이 GCC가 /usr/bin/gcc로 사용 가능하며, Chapter 8의 모든 패키지를 네이티브로 빌드할 수 있습니다.

Chroot 환경 진입

모든 크로스 컴파일 패키지가 설치되었으므로, 이제 Chroot 환경에 진입합니다.

Chroot란 무엇인가? chroot(2) 시스템 콜(System Call)은 현재 프로세스와 그 자손 프로세스의 루트 디렉토리(/)를 지정된 경로로 교체합니다. chroot $LFS /usr/bin/bash를 실행하면 Bash는 $LFS를 /로 인식하고, /usr/lib/libc.so는 실제로 $LFS/usr/lib/libc.so를 가리킵니다. 호스트의 파일 시스템은 완전히 가려지므로 호스트 라이브러리나 헤더가 섞일 위험이 없습니다.

왜 VFS 바인드 마운트(Bind Mount)가 필요한가? chroot는 파일 시스템 경로만 바꾸며, 커널 가상 파일시스템(VFS, Virtual File System)인 /proc(프로세스 정보), /sys(커널 오브젝트), /dev(디바이스 노드)는 별도로 제공해야 합니다. 이 파일들은 커널이 실시간으로 생성하는 특수 파일이므로, 호스트의 마운트 포인트를 $LFS/proc 등으로 바인드 마운트하여 Chroot 안에서도 커널 인터페이스를 정상 사용할 수 있게 합니다.

소유권 변경

# lfs 사용자에서 root로 전환
exit  # lfs 사용자 로그아웃

# $LFS 전체를 root 소유로 변경
sudo chown -R root:root $LFS/{usr,lib,var,etc,bin,sbin,tools}
case $(uname -m) in
  x86_64) sudo chown -R root:root $LFS/lib64 ;;
esac

가상 파일시스템(VFS) 마운트

# 가상 커널 파일시스템 마운트
mkdir -pv $LFS/{dev,proc,sys,run}

# /dev 바인드 마운트
mount -v --bind /dev $LFS/dev

# devpts 마운트
mount -vt devpts devpts -o gid=5,mode=0620 $LFS/dev/pts

# proc, sysfs, tmpfs 마운트
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run

# /dev/shm 처리
if [ -h $LFS/dev/shm ]; then
  install -v -d -m 1777 $LFS$(realpath /dev/shm)
else
  mount -vt tmpfs -o nosuid,nodev tmpfs $LFS/dev/shm
fi
Chroot 환경 — $LFS가 새로운 루트(/)가 되어 호스트로부터 완전히 격리됩니다 Chroot 환경 — 루트 디렉토리 관점의 변화 chroot(2)가 루트를 /에서 $LFS로 교체 — 호스트의 하위 디렉토리가 새로운 독립 시스템의 루트가 됩니다 호스트 시스템 — chroot 실행 전 루트(/) 아래에서 $LFS는 하나의 디렉토리일 뿐 / (호스트 루트) /usr 호스트 gcc·glibc /proc · /sys · /dev 커널 인터페이스 /mnt/lfs = $LFS $LFS = /mnt/lfs — LFS 시스템 콘텐츠 usr GCC Pass 2 · glibc tools 크로스 도구 sources 소스 타르볼 chroot되면 이 트리 전체가 새 루트(/)가 됩니다 chroot 전 — 루트는 호스트의 / chroot(2) 루트 교체 Chroot 환경 — LFS 시스템 (실행 후) 루트가 $LFS로 교체 — 호스트와 완전 격리 / (구 $LFS) /usr LFS gcc·glibc /bin · /sbin · /lib LFS 바이너리 /tools · sources 빌드 자료 커널 인터페이스 — 호스트에서 바인드 마운트로 제공 /proc 바인드 마운트 /sys 바인드 마운트 /dev 바인드 마운트 ✗ 호스트 파일시스템에 접근 불가 독립적 시스템 — 오염 불가능
Chroot 환경 — $LFS가 새로운 루트(/)가 되어 호스트로부터 완전히 격리

Chroot 진입

chroot "$LFS" /usr/bin/env -i   \
    HOME=/root                  \
    TERM="$TERM"                \
    PS1='(lfs chroot) \u:\w\$ ' \
    PATH=/usr/bin:/usr/sbin     \
    MAKEFLAGS="-j$(nproc)"      \
    TESTSUITEFLAGS="-j$(nproc)" \
    /bin/bash --login

필수 디렉토리 생성

# FHS 디렉토리 구조 생성
mkdir -pv /{boot,home,mnt,opt,srv}

mkdir -pv /etc/{opt,sysconfig}
mkdir -pv /lib/firmware
mkdir -pv /media/{floppy,cdrom}
mkdir -pv /usr/{,local/}{include,src}
mkdir -pv /usr/lib/locale
mkdir -pv /usr/local/{bin,lib,sbin}
mkdir -pv /usr/{,local/}share/{color,dict,doc,info,locale,man}
mkdir -pv /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
mkdir -pv /var/{cache,local,log,mail,opt,spool}
mkdir -pv /var/lib/{color,misc,locate}

ln -sfv /run /var/run
ln -sfv /run/lock /var/lock

install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp

필수 파일 생성

# /etc/passwd 초기 설정
cat > /etc/passwd << "EOF"
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/dev/null:/usr/bin/false
daemon:x:6:6:Daemon User:/dev/null:/usr/bin/false
messagebus:x:18:18:D-Bus Message Daemon User:/run/dbus:/usr/bin/false
systemd-journal-gateway:x:73:73:systemd Journal Gateway:/:/usr/bin/false
systemd-journal-remote:x:74:74:systemd Journal Remote:/:/usr/bin/false
systemd-journal-upload:x:75:75:systemd Journal Upload:/:/usr/bin/false
systemd-network:x:76:76:systemd Network Management:/:/usr/bin/false
systemd-resolve:x:77:77:systemd Resolver:/:/usr/bin/false
systemd-timesync:x:78:78:systemd Time Synchronization:/:/usr/bin/false
systemd-coredump:x:79:79:systemd Core Dumper:/:/usr/bin/false
uuidd:x:80:80:UUID Generation Daemon:/dev/null:/usr/bin/false
systemd-oom:x:81:81:systemd Out Of Memory Daemon:/:/usr/bin/false
nobody:x:65534:65534:Unprivileged User:/dev/null:/usr/bin/false
EOF

# /etc/group 초기 설정
cat > /etc/group << "EOF"
root:x:0:
bin:x:1:daemon
sys:x:2:
kmem:x:3:
tape:x:4:
tty:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
cdrom:x:15:
adm:x:16:
messagebus:x:18:
systemd-journal:x:23:
input:x:24:
mail:x:34:
kvm:x:61:
systemd-journal-gateway:x:73:
systemd-journal-remote:x:74:
systemd-journal-upload:x:75:
systemd-network:x:76:
systemd-resolve:x:77:
systemd-timesync:x:78:
systemd-coredump:x:79:
uuidd:x:80:
systemd-oom:x:81:
wheel:x:97:
users:x:999:
nogroup:x:65534:
EOF
Chroot 실패 시: chroot: failed to run command '/bin/bash': No such file or directory가 나타나면 가상 파일시스템 마운트를 확인하세요. 또한 $LFS/usr/bin/bash가 존재하고 올바른 동적 링커(ld-linux-x86-64.so.2)에 링크되어 있는지 확인하세요.

기본 시스템 소프트웨어

Chroot 환경에 진입한 후, Chapter 8에서는 83개의 패키지를 최종 빌드합니다. 이 단계에서는 Pass 2에서 빌드한 네이티브 GCC를 사용하여 모든 패키지를 다시 빌드합니다.

주요 패키지 빌드 의존성 순서 — 패키지는 의존성 순서에 따라 빌드해야 하며 대부분 Glibc를 기반으로 함 주요 패키지 빌드 의존성 순서 빌드 순서 Linux Headers 커널 API 헤더 · 최초 빌드 Glibc C 표준 라이브러리 · 모든 패키지의 기반 Zlib 압축 라이브러리 Bzip2 블록 정렬 압축 Readline 명령줄 편집 라이브러리 Ncurses 터미널 라이브러리 Binutils 어셈블러·링커 GCC C/C++ 컴파일러 ※ GCC 빌드 전 GMP·MPFR·MPC 선행 빌드 Coreutils 기본 유틸리티 Perl 인터프리터 Bash 셸 · Readline에 의존 Python 인터프리터 Util-linux 시스템 유틸리티 Systemd 시스템 초기화 D-Bus IPC 버스 기반 — Linux Headers 툴체인 — Glibc·Binutils·GCC 공용 라이브러리 — Zlib·Bzip2·Readline·Ncurses 셸·인터프리터·유틸 — Bash·Coreutils·Perl·Python 시스템 인프라 — Util-linux·Systemd·D-Bus 읽는 법: 위 → 아래가 빌드 순서 · 화살표 A→B는 B가 A에 의존(A를 먼저 빌드) · 세로 바는 Glibc의 의존성 분배 ※ Zlib 등 초기 공용 라이브러리는 7장까지의 임시 툴체인으로 빌드하며, 이후 모든 패키지가 Glibc를 기반으로 빌드됨
주요 패키지 빌드 의존성 — 패키지는 의존성 순서에 따라 빌드해야 함

일반 빌드 패턴

# Chapter 8 표준 빌드 절차
cd /sources
tar -xf <package>-<version>.tar.xz
cd <package>-<version>

# 빌드 디렉토리 (필요한 패키지만)
mkdir build && cd build

# configure, make, test, install
./configure --prefix=/usr [옵션들...]
make
make check        # 테스트 스위트 (선택사항이지만 권장)
make install

# 소스 정리
cd /sources
rm -rf <package>-<version>
테스트 스위트: make check으로 테스트를 실행하는 것은 선택사항이지만 강력히 권장됩니다. 특히 GCC, Glibc, Binutils의 테스트는 반드시 실행하세요. 일부 테스트 실패는 알려진 문제일 수 있으므로 LFS 책의 해당 패키지 섹션에서 예상 실패 목록을 확인하세요.

주요 패키지 빌드 하이라이트

Glibc (최종 빌드)

Chapter 8에서 Glibc를 다시 빌드합니다. 이번에는 네이티브 컴파일러를 사용하며, 로케일, NSS, 타임존 등의 전체 기능이 포함됩니다.

GCC (최종 빌드)

Chapter 8의 GCC는 모든 최적화와 기능이 활성화된 완전한 컴파일러입니다. 테스트 스위트를 반드시 실행하세요:

# GCC 테스트 스위트 실행
make -k check
# 일부 실패는 알려진 문제 — LFS 책 참조
디버그 심볼 제거: 최종 시스템에서 디버그 심볼을 제거하면 약 2GB의 디스크 공간을 절약할 수 있습니다:
# 라이브러리와 바이너리에서 디버그 심볼 제거
save_usrlib="ld-linux-x86-64.so.2 libc.so.6 libthread_db.so.1 libquadmath.so.0
             libstdc++.so.6 libitm.so.1 libatomic.so.1"
cd /usr/lib
for LIB in $save_usrlib; do
    objcopy --only-keep-debug --compress-debug-sections=zlib $LIB $LIB.dbg
    cp $LIB /tmp/$LIB
    strip --strip-unneeded /tmp/$LIB
    objcopy --add-gnu-debuglink=$LIB.dbg /tmp/$LIB
    install -vm755 /tmp/$LIB /usr/lib
    rm /tmp/$LIB
done

# 나머지 라이브러리
find /usr/lib -type f -name \*.a \
   -exec strip --strip-debug {} ';'
find /usr/lib -type f -name \*.so* ! -name \*dbg \
   -exec strip --strip-unneeded {} ';'
find /usr/{bin,sbin,libexec} -type f \
   -exec strip --strip-all {} ';'

패키지 관리 전략

LFS에는 공식 패키지 매니저가 없습니다. 시스템을 유지보수하고 업데이트하려면 자체 패키지 관리 전략이 필요합니다. 패키지 관리는 LFS 빌드 이후 시스템을 장기적으로 유지하는 데 가장 중요한 결정 중 하나입니다.

패키지 관리 전략 비교 — 난이도 대비 기능이 균형 잡힌 DESTDIR 아카이브 권장 LFS 패키지 관리 전략 — 난이도 vs 기능 비교 구현 난이도 → 기능 완성도 ↑ 낮음 중간 높음 낮음 중간 높음 Timestamp 기반 설치 전후 비교 DESTDIR 아카이브 tar.gz 패키징 ★ LFS 권장 Symlink (Stow) 별도 디렉토리 + 링크 Install 추적 LD_PRELOAD hook RPM/dpkg 완전한 패키지 매니저 ※ 축 위치는 정성적 단계(낮음/중간/높음) 비교이며, 실제 측정값이 아닙니다.
패키지 관리 전략 비교 — DESTDIR 아카이브가 난이도 대비 기능이 가장 균형 잡힌 전략

패키지 관리 전략 비교

전략방법장점단점
별도 디렉토리 설치 --prefix=/usr/pkg/<name>-<ver>로 설치 후 심볼릭 링크 깔끔한 분리, 쉬운 제거 복잡한 심볼릭 링크 관리
Symlink 스타일 Stow/GNU Stow로 심볼릭 링크 자동 관리 표준화된 도구 사용 Stow 의존성
Timestamp 기반 설치 전후 파일 타임스탬프 비교 구현 간단 동시 빌드 불가, 부정확할 수 있음
Install 추적 LD_PRELOAD로 install() 시스템 콜 가로채기 정확한 파일 추적 구현 복잡
패키지 아카이브 DESTDIR로 가상 설치 후 .tar.gz로 아카이브 재현성, 백업, 배포 용이 추가 디스크 공간 필요
RPM/dpkg 도입 LFS 위에 RPM 또는 dpkg 패키지 매니저 설치 완전한 패키지 관리 설정 복잡, LFS 정신에 반함
권장 전략: 패키지 아카이브
# DESTDIR로 가상 설치
make DESTDIR=/tmp/pkg-<name>-<ver> install

# 아카이브 생성
cd /tmp/pkg-<name>-<ver>
tar czf /packages/<name>-<ver>.tar.gz .

# 실제 설치
tar xzf /packages/<name>-<ver>.tar.gz -C /

# 제거 시: tar 내용 목록으로 파일 삭제
tar tzf /packages/<name>-<ver>.tar.gz | xargs rm -f

커널 컴파일 및 설치

LFS 시스템의 핵심인 리눅스 커널을 컴파일합니다. 커널 설정은 LFS가 부팅 가능한지 여부를 결정하는 가장 중요한 단계 중 하나입니다.

커널 컴파일 과정 커널 컴파일 과정 빌드 단계 작업 위치: /sources/linux-6.18.10 ① 소스 준비 cd /sources tar -xf · make mrproper ② 커널 설정 make menuconfig 산출물: .config ③ 컴파일 make (병렬 빌드) 산출물: bzImage · System.map 설치 단계 ④ 모듈 설치 make modules_install → /lib/modules/6.18.10/ 커널 모듈(.ko) ⑤ 커널 이미지 복사 cp -iv arch/x86/boot/bzImage → /boot/ vmlinuz-6.18.10-lfs-13.0-systemd ⑥ System.map 복사 cp -iv System.map → /boot/ System.map-6.18.10 ⑦ .config 백업 cp -iv .config → /boot/ config-6.18.10
커널 컴파일 과정 — 소스 준비부터 /boot 설치까지

빌드 절차

cd /sources
tar -xf linux-6.18.10.tar.xz
cd linux-6.18.10

# 소스 클린
make mrproper

# 커널 설정 (ncurses 메뉴)
make menuconfig

# 컴파일 (병렬 빌드)
make

# 모듈 설치
make modules_install

# 커널 이미지 복사
cp -iv arch/x86/boot/bzImage /boot/vmlinuz-6.18.10-lfs-13.0-systemd

# System.map 복사 (디버깅용)
cp -iv System.map /boot/System.map-6.18.10

# 커널 설정 파일 백업
cp -iv .config /boot/config-6.18.10

# 커널 문서 설치 (선택)
install -d /usr/share/doc/linux-6.18.10
cp -r Documentation/* /usr/share/doc/linux-6.18.10

LFS에 필수적인 커널 설정 옵션

옵션값설명
CONFIG_DEVTMPFS=ydevtmpfs 지원 (필수! udev 전에 /dev 채움)
CONFIG_DEVTMPFS_MOUNT=ydevtmpfs를 /dev에 자동 마운트 (LFS 부팅에 필수)
CONFIG_CGROUPS=ycgroups v2 지원 (systemd 필수)
CONFIG_INOTIFY_USER=yinotify 지원 (udev, systemd 필요)
CONFIG_SIGNALFD=ysignalfd 지원 (systemd 필요)
CONFIG_TIMERFD=ytimerfd 지원 (systemd 필요)
CONFIG_EPOLL=yepoll 지원 (systemd 필요)
CONFIG_TMPFS=ytmpfs 지원 (/tmp, /run)
CONFIG_TMPFS_POSIX_ACL=ytmpfs POSIX ACL (systemd 필요)
CONFIG_DMIID=yDMI 테이블 (systemd-hostnamed 필요)
CONFIG_EXT4_FS=yext4 파일시스템 (내장, 모듈 아님)
CONFIG_PARTITION_ADVANCED=y고급 파티션 지원
CONFIG_EFI_STUB=yEFI 스텁 (UEFI 부팅 시 필요)
CONFIG_DEVTMPFS_MOUNT=y는 LFS 부팅의 핵심! 이 옵션이 없으면 부팅 시 /dev에 디바이스 노드가 생성되지 않아 root 파일시스템 마운트에 실패합니다. 반드시 =y로 내장하세요 (모듈이 아님).

initramfs와 루트 파일시스템 마운트

LFS 본책은 initramfs 없이 커널이 루트 파일시스템을 직접 마운트하는 구조를 전제로 합니다. 루트 파일시스템 드라이버(예: ext4)와 디스크 컨트롤러 드라이버를 커널에 내장(=y)으로 빌드했기 때문에, 커널은 부팅 직후 바로 루트를 찾아 마운트하고 /sbin/init (systemd)을 실행할 수 있습니다.

그러나 다음과 같은 환경에서는 initramfs(초기 RAM 파일시스템)가 필요합니다.

증상: initramfs가 필요한 환경에서 initramfs 없이 부팅하면 커널이 루트를 찾지 못해 VFS: Unable to mount root fs on unknown-block(...) 팬릭(Panic)이 발생합니다. 이 경우 루트 관련 드라이버를 모두 =y로 내장하거나, initramfs를 생성하면 해결됩니다.
직접 마운트 vs initramfs 부팅 비교 루트 파일시스템 접근 방식 : 직접 마운트 vs initramfs LFS 기본 : 직접 마운트 initramfs 없음 — 커널 내장 드라이버만 사용 1 GRUB 커널(vmlinuz) 로드 2 Linux 커널 내장(=y) 드라이버로 장치 초기화 3 루트 직접 마운트 커널이 root=/dev/sda1 직접 마운트 4 systemd (PID 1) 실제 루트에서 서비스 시작 경로 4단계 — 커널이 전담하므로 가장 단순합니다 initramfs 사용 복잡한 루트 장치 — LVM · RAID · dm-crypt 1 GRUB 커널 + initramfs 로드 2 Linux 커널 initramfs를 임시 루트로 시동 3 initramfs /init 임시 루트에서 실제 루트 준비 4 실제 루트 마운트 마운트 지점 : /sysroot 5 pivot_root() 실제 루트로 전환 · 임시 루트 해제 6 systemd (PID 1) 실제 루트에서 서비스 시작 경로 6단계 — 복잡한 루트 장치를 도구로 준비 후 전환 공통 : 두 방식 모두 실제 루트에서 systemd(PID 1)가 서비스를 시작합니다
직접 마운트 vs initramfs 부팅 — LFS 기본은 initramfs 없이 커널이 루트를 직접 마운트하고, 복잡한 루트 장치에서는 initramfs가 드라이버와 도구를 먼저 준비한 뒤 pivot_root()로 전환합니다
initramfs 생성: initramfs 생성 도구(dracut, initramfs-tools 등)는 LFS 본책 범위를 벗어나므로 BLFS의 관련 장을 참고하세요. 커널에 내장할 수도 있으며(CONFIG_INITRAMFS_SOURCE), 이 경우 별도의 /boot 파일 없이 커널 이미지 안에 들어갑니다. GRUB에서는 initrd /boot/initramfs-6.18.10.img 한 줄로 로드합니다.

GRUB 부트로더 설정

GRUB(GRand Unified Bootloader)은 시스템 시작 시 커널을 로드하는 부트로더입니다. LFS에서는 GRUB 2를 사용합니다.

부팅 과정 LFS 부팅 과정 : 전원 인가부터 로그인 프롬프트까지 5단계 흐름 1 2 3 4 5 BIOS/UEFI 펌웨어 단계 GRUB 부트로더 단계 Linux 커널 커널 단계 systemd (PID 1) 사용자 공간 단계 Login 사용자 공간 단계 • 하드웨어 초기화 (POST) • 부팅 매체에서 GRUB 실행 • BIOS(MBR) · UEFI(ESP) • grub.cfg 메뉴 읽기 • vmlinuz 메모리 로드 • root= 파라미터 전달 • 아키텍처·드라이버 초기화 • 루트 파일시스템 직접 마운트 • systemd (PID 1) 실행 • /etc/fstab → 마운트 유닛 • swap, /proc, /sys, /run • multi-user.target 시작 • getty → 로그인 프롬프트 • /bin/login 인증 • bash 로그인 셸 실행 핵심 경로 : GRUB의 root=로 커널이 루트를 직접 마운트하고, systemd(PID 1)가 서비스와 로그인을 준비합니다
LFS 부팅 과정(Boot Process) — BIOS/UEFI → GRUB → Kernel → systemd → Login

GRUB 설치

# BIOS 시스템 (MBR)
grub-install /dev/sdb

# UEFI 시스템
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=LFS

grub.cfg 설정

cat > /boot/grub/grub.cfg << "EOF"
# /boot/grub/grub.cfg - LFS 13.0-systemd

set default=0
set timeout=5

insmod ext2
set root=(hd0,1)
# 또는 UUID 사용: search --no-floppy --fs-uuid --set=root <UUID>

menuentry "GNU/Linux, Linux 6.18.10-lfs-13.0-systemd" {
    linux /boot/vmlinuz-6.18.10-lfs-13.0-systemd root=/dev/sda1 ro
}

menuentry "Firmware Setup" {
    fwsetup
}
EOF
root= 파라미터 확인: root=/dev/sda1은 LFS 루트 파티션을 가리켜야 합니다. 잘못된 파티션을 지정하면 kernel panic - not syncing: VFS: Unable to mount root fs 오류가 발생합니다. UUID를 사용하는 것이 더 안전합니다: root=UUID=<blkid 출력값>

BIOS vs UEFI

항목BIOS (Legacy)UEFI
파티션 테이블MBRGPT
GRUB 설치 위치MBR + /boot/grubEFI System Partition
부팅 파일core.imggrubx64.efi
설치 명령grub-install /dev/sdbgrub-install --target=x86_64-efi
Secure Boot지원 안 함선택적 지원

systemd 설정

LFS 13.0-systemd는 init 시스템으로 systemd를 사용합니다. systemd는 서비스 관리, 로깅, 네트워크, 타임존, 로케일 등 시스템 전반의 설정을 통합 관리합니다.

Machine ID 생성

# 고유 Machine ID 생성 (첫 부팅 전에 필요)
systemd-machine-id-setup

호스트명 설정

echo "lfs-system" > /etc/hostname

# /etc/hosts 설정
cat > /etc/hosts << "EOF"
127.0.0.1  localhost
127.0.1.1  lfs-system
::1        localhost ip6-localhost ip6-loopback
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
EOF

로케일 설정

# 사용 가능한 로케일 생성
localedef -i ko_KR -f UTF-8 ko_KR.UTF-8
localedef -i en_US -f UTF-8 en_US.UTF-8

# 시스템 로케일 설정
cat > /etc/locale.conf << "EOF"
LANG=ko_KR.UTF-8
EOF

시간대 설정

# 시간대 설정
ln -sfv /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# 또는 timedatectl 사용 (systemd 부팅 후)
# timedatectl set-timezone Asia/Seoul

네트워크 설정 (systemd-networkd)

# 유선 네트워크 DHCP 설정
cat > /etc/systemd/network/10-eth-dhcp.network << "EOF"
[Match]
Name=en*

[Network]
DHCP=ipv4

[DHCPv4]
UseDomains=true
EOF

# 또는 고정 IP 설정
cat > /etc/systemd/network/10-eth-static.network << "EOF"
[Match]
Name=en*

[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
EOF

# systemd-networkd 및 systemd-resolved 활성화
systemctl enable systemd-networkd
systemctl enable systemd-resolved

# /etc/resolv.conf 심볼릭 링크
ln -sfv /run/systemd/resolve/resolv.conf /etc/resolv.conf

콘솔 설정

# 키보드 레이아웃 설정
cat > /etc/vconsole.conf << "EOF"
KEYMAP=us
EOF
systemd 저널: systemd는 syslog 대신 journald를 사용합니다. journalctl 명령으로 로그를 확인할 수 있습니다:
journalctl -b           # 현재 부팅 로그
journalctl -u sshd      # 특정 서비스 로그
journalctl --since today # 오늘 로그

/etc/fstab 설정

/etc/fstab(파일시스템 테이블)은 부팅 시 마운트할 파일시스템을 정의합니다. systemd는 systemd-fstab-generator로 이 파일을 읽어 마운트 유닛(mount unit)을 생성합니다. 반드시 필요한 파일은 아니지만, 루트 파일시스템의 마운트 옵션·검사(pass) 순서를 지정하고 스왑(Swap)·추가 파티션을 부팅 시 자동 마운트하려면 작성해야 합니다.

# 파일시스템    마운트 지점   타입    옵션                      덤프  패스
/dev/sda1      /             ext4    defaults                  1     1
/dev/sda2      swap          swap    pri=1                     0     0
proc           /proc         proc    nosuid,noexec,nodev       0     0
sysfs          /sys          sysfs   nosuid,noexec,nodev       0     0
devpts         /dev/pts      devpts  gid=5,mode=620,ptmxmode=0666  0     0
tmpfs          /run          tmpfs   mode=0755,nosuid,nodev    0     0
tmpfs          /dev/shm      tmpfs   nosuid,nodev              0     0
systemd에서의 fstab: /proc, /sys, /dev/pts, /run은 systemd가 기본적으로 자동 마운트하므로 fstab에 없어도 동작하지만, 명시해 두면 옵션을 직접 제어할 수 있습니다. systemctl daemon-reload 후 systemctl list-units --type=mount로 생성된 마운트 유닛을 확인할 수 있습니다.

부팅 성능 분석 (systemd-analyze)

부팅이 완료된 후 systemd-analyze로 부팅 시간과 병목(Bottleneck) 서비스를 분석할 수 있습니다.

systemd-analyze                  # 커널 + 사용자 공간 부팅 시간 요약
systemd-analyze blame            # 서비스별 시작 지연 (내림차순)
systemd-analyze critical-chain   # 부팅 임계 경로 (Critical Chain)
journalctl --disk-usage          # 저널 디스크 사용량
systemctl list-units --failed    # 실패한 유닛 확인
blame 출력 해석: systemd-analyze blame의 수치는 해당 서비스가 시작 완료까지 기다린 지연(Latency) 시간입니다. 값이 큰 서비스가 항상 문제인 것은 아니며, systemd-analyze critical-chain로 실제로 부팅 경로를 지연시키는 서비스를 찾는 것이 정확합니다.

전체 패키지 목록

LFS 13.0-systemd에 포함되는 83개 패키지의 전체 목록입니다. 패키지는 기능별로 분류되어 있습니다.

핵심 시스템 라이브러리

#패키지버전크기 (KB)설명
1Glibc2.4319,821GNU C 라이브러리
2Zlib1.3.21,468압축 라이브러리
3Bzip21.0.8791블록 정렬 압축
4Xz Utils5.8.21,476LZMA 압축
5Zstd1.5.72,378Zstandard 압축
6Readline8.33,339명령줄 편집 라이브러리
7Ncurses6.63,702터미널 라이브러리
8Libffi3.5.21,390Foreign Function Interface
9OpenSSL3.6.153,605암호화(Encryption) 라이브러리
10Expat2.7.4495XML 파서
11Libelf (elfutils)0.19411,722ELF 라이브러리
12Libpipeline1.5.81,045파이프라인 라이브러리
13Pcre210.472,095정규표현식(Regular Expression) 라이브러리

빌드 도구

#패키지버전크기 (KB)설명
14Binutils2.46.027,880어셈블러, 링커
15GCC15.2.098,688C/C++ 컴파일러
16GMP6.3.02,045다중 정밀도 수학
17MPFR4.2.21,470다중 정밀도 부동소수점
18MPC1.3.1755다중 정밀도 복소수
19Make4.4.12,293빌드 자동화
20Autoconf2.721,357configure 스크립트 생성기
21Automake1.18.11,614Makefile 생성기
22Libtool2.5.41,032라이브러리 빌드 도구
23Pkgconf2.5.1320컴파일러 플래그 관리
24M41.4.212,031매크로 프로세서
25Bison3.8.22,751파서 생성기
26Flex2.6.41,386렉서 생성기

핵심 유틸리티

#패키지버전크기 (KB)설명
27Coreutils9.106,355ls, cp, mv 등 기본 유틸리티
28Bash5.311,090Bourne-Again Shell
29Grep3.121,873패턴 검색
30Sed4.91,364스트림 편집기
31Gawk5.3.23,661텍스트 처리
32Findutils4.10.02,188파일 검색
33Diffutils3.121,893파일 비교
34Patch2.8886패치 적용
35Tar1.352,263아카이브
36Gzip1.14865압축
37File5.461,282파일 타입 판별

시스템 관리

#패키지버전크기 (KB)설명
38Util-linux2.41.39,245시스템 유틸리티 (mount, fdisk 등)
39Systemd259.116,869init 시스템, 서비스 관리
40D-Bus1.16.21,089IPC 메시지 버스(Bus)
41Procps-ng4.0.62,282프로세스 유틸리티 (ps, top)
42Psmisc23.7396pstree, fuser, killall
43E2fsprogs1.47.39,830ext2/3/4 파일시스템 도구
44Shadow4.19.32,293패스워드, 사용자 관리
45Kmod34.2433커널 모듈(Kernel Module) 관리 (modprobe)
46Kbd2.9.01,492키보드 유틸리티
47Lz41.10.0378LZ4 압축
48GDBM1.261,198데이터베이스 라이브러리
49Iana-Etc20260202593네트워크 서비스·프로토콜 번호 데이터

스크립트 언어 및 텍스트 처리

#패키지버전크기 (KB)설명
50Perl5.42.014,063스크립트 언어
51Python 33.14.323,221스크립트 언어
52XML::Parser (Perl)2.47272Perl XML 파서 모듈
53Intltool0.51.0158국제화 도구
54Gettext1.010,470다국어 지원
55Texinfo7.26,258문서 시스템
56Groff1.23.07,259텍스트 포맷터 (man 페이지(Page))
57Man-DB2.13.12,048man 페이지 관리
58Man-pages6.171,852리눅스 man 페이지
59Tcl8.6.1711,264스크립트 언어 (테스트 도구용)
60Expect5.45.4618자동화 대화형 프로그램
61DejaGNU1.6.3607테스트 프레임워크

네트워킹 및 보안

#패키지버전크기 (KB)설명
62Iproute26.18.0923네트워크 설정 (ip, ss)
63Libcap2.77195POSIX capabilities
64Acl2.3.2363접근 제어(Access Control) 리스트
65Attr2.5.2481확장 속성(Extended Attribute)
66Libxcrypt4.5.2654crypt 라이브러리

기타 핵심 패키지

#패키지버전크기 (KB)설명
67Linux Kernel6.18.10150,742리눅스 커널
68GRUB2.147,545부트로더
69Less692964텍스트 뷰어
70Vim9.2.007819,292텍스트 에디터
71MarkupSafe3.0.378Python HTML 이스케이프
72Jinja23.1.6239Python 템플릿 엔진
73Wheel0.46.359Python 패키지 포맷
74Setuptools82.0.01,118Python 빌드 시스템
75Meson1.10.12,357빌드 시스템
76Ninja1.13.2286빌드 러너
77Inetutils2.73,084네트워크 유틸리티 (hostname, ping)
78Gperf3.31,788완벽 해시 함수 생성기
79Bc7.0.3464계산기
80Sqlite3.51.23,133경량 임베디드 데이터베이스
81Packaging26.0140Python 패키징 유틸리티
82Flit-core3.12.052Python 빌드 백엔드
83Tzdata2025c458시간대(Timezone) 데이터
13.0 구성 변화: 13.0부터 systemd 에디션만 정기 갱신됨에 따라 Sysvinit·Eudev·LFS-Bootscripts는 목록에서 제외되고, Pcre2·Lz4·Sqlite·Iana-Etc·Tzdata·Packaging, 그리고 테스트용 Tcl/Expect/DejaGNU가 추가되었습니다. 크기는 공식 다운로드 타르볼(소스) 기준이며, 문서 전용(docs) 타르볼은 제외했습니다. 최신 해시/버전은 Chapter 3 packages.html에서 확인하세요.

Cross Build 실행 계획 (세분화)

아래 계획은 https://www.linuxfromscratch.org/lfs/view/stable-systemd/의 Chapter 5~7 구조를 그대로 따르면서, 실제 작업 시 실패 지점을 조기에 차단하도록 검증 단계를 촘촘히 추가한 확장형 런북입니다. 특히 Cross build 단계(Chapter 5, 6)에 집중해 옵션 누락·호스트 오염·링커 경로 오류를 빠르게 식별하도록 구성했습니다.

Phase대상 장핵심 목표완료 조건실패 시 즉시 조치
0Ch.2~4호스트/환경 정합성 확보version-check.sh 통과, /bin/sh -> bash호스트 패키지/심볼릭 링크 재정렬
1Ch.5Cross Toolchain 구축Binutils/GCC/Glibc/Libstdc++ 빌드 + sanity check 통과문제 패키지부터 Ch.5 재시작(Reboot)
2Ch.6임시 도구 Cross Compile모든 임시 패키지 --host=$LFS_TGT 빌드 성공환경 변수/DESTDIR/PATH 재검증
3Ch.6Binutils/GCC Pass 2네이티브 진입용 컴파일러 완료--with-build-sysroot, LDFLAGS_FOR_TARGET 재점검
4Ch.7Chroot 전환/tools/bin 미사용 상태로 셸 진입가상 파일시스템 재마운트 후 재진입
5Ch.8+최종 시스템 빌드패키지 테스트/설치 및 부팅 성공실패 패키지 재빌드 + 로그 비교
Cross build 핵심 원칙: Chapter 5~6은 "현재 호스트를 사용하면서도 결과물은 LFS 전용으로 격리"하는 단계입니다. 이 단계가 불완전하면 Chroot 이후에 랜덤하게 깨지므로, 빌드 성공보다 경로/링크/동적 로더(Loader) 검증이 더 중요합니다.

stable-systemd 버전 동기화 포인트

LFS stable-systemd 인덱스(Version 13.0-systemd, 2026-03-05 릴리스) 기준으로 Cross build에 직접 영향을 주는 주요 버전은 다음과 같습니다. 기존 12.4 기준은 참고용으로 병기했으며, 실제 작업 시 Chapter 3 packages.html에서 최신 해시/버전을 확인하세요.

컴포넌트13.0-systemd (최신)12.4-systemd (이전)Cross build 영향
Binutils Pass 1/22.462.45링커 기본 동작 및 DTAGS/hash 스타일, relocatable 출력
GCC Pass 1/215.2.0+15.2.0libgcc, libstdc++, PIE/SSP 기본값, _FORTIFY_SOURCE 레벨
Linux API Headers6.18.x6.16.1glibc가 참조하는 커널 UAPI 인터페이스 (syscall 번호/구조체)
Glibc2.432.42동적 로더 경로, CRT 파일, libc ABI, NSS 플러그인 구조
systemd258 계열257.8최종 사용자 공간 init 동작(Ch.8 이후), BPF/sandbox 기본값
Python (유틸)3.14.x3.13.xmeson/자동화 스크립트 최소 요구 버전 영향
운영 팁: 문서 본문 예시 버전과 실제 stable-systemd 버전이 다르면, configure 옵션은 유지하고 버전 문자열/경로만 우선 치환한 뒤 테스트를 재실행하세요. 13.0으로 이행할 때 주요 함정은 (1) Binutils 2.46의 기본 --hash-style 변화 여부, (2) Glibc 2.43의 새 NSS 기본값, (3) 커널 6.18 UAPI가 요구하는 최소 glibc·gcc 버전입니다. stable-systemd 책의 Important Package Information 박스를 반드시 먼저 읽고 반영하세요.
12.4 → 13.0 마이그레이션 체크리스트:
  1. Binutils 2.45 → 2.46: 일부 어셈블러 옵션 경고 강화. configure에 --enable-new-dtags 명시 유지.
  2. Glibc 2.42 → 2.43: /etc/nsswitch.conf 템플릿 재검토. ldconfig 캐시 형식 변경 여부 확인.
  3. 커널 6.16 → 6.18: 헤더 재설치 후 glibc 재빌드 필수. linux-libc-dev 계열 호스트와 혼동 주의.
  4. 보안 패치 재동기화: expat, openssl, zlib, vim 등 13.0에서 올라간 CVE 대응 버전을 기존 12.4 빌드 트리에 소급 적용할 때는 ABI 호환성 확인.
  5. systemd 258 계열: unit 파일 Stop/Restart 정책의 기본값이 일부 바뀌었으므로 서비스 재검증.

Cross Build 사전 점검 체크리스트

Chapter 5 시작 전에 반드시 아래 항목을 고정합니다. 한 항목이라도 흔들리면 원인 추적 시간이 급격히 증가합니다.

  1. 사용자 격리: Ch.5~6은 반드시 lfs 사용자로 실행 (root 금지)
  2. 환경 초기화: exec env -i ... /bin/bash 기반 깨끗한 셸 사용
  3. 핵심 변수: LFS, LFS_TGT, PATH=$LFS/tools/bin:..., LC_ALL=POSIX
  4. 소스 무결성(Integrity): 패키지/패치 해시 점검 후 시작
  5. 디스크 여유: 빌드 로그/테스트까지 고려해 충분한 공간 확보
# Cross build 시작 전 최소 확인 스크립트
echo "LFS=$LFS"
echo "LFS_TGT=$LFS_TGT"
echo "$PATH" | tr ':' '\n' | head -n 3
id
pwd
mount | grep "$LFS"

# 도구 해상도 확인
which $LFS_TGT-gcc
which $LFS_TGT-ld

# 오염 가능 변수 제거 여부 확인
env | grep -E '^(CC|CXX|LD|AR|AS|CFLAGS|CXXFLAGS|LDFLAGS|PKG_CONFIG_PATH)='

Chapter 5 Cross Toolchain 런북 (강화판)

stable-systemd Chapter 5의 핵심은 "가짜 cross-compilation처럼 보이지만 실제 cross-toolchain 원칙을 그대로 적용"하는 데 있습니다. 도구는 $LFS/tools에 분리하고, 라이브러리는 최종 위치로 배치하여 Chroot 전환을 준비합니다.

1) Binutils Pass 1 (기본 골격)

mkdir -v build
cd build
../configure --prefix=$LFS/tools \
             --with-sysroot=$LFS \
             --target=$LFS_TGT   \
             --disable-nls       \
             --enable-gprofng=no \
             --disable-werror    \
             --enable-new-dtags  \
             --enable-default-hash-style=gnu
make
make install

2) GCC Pass 1 (glibc 없는 최소 C/C++)

mkdir -v build
cd build
../configure                  \
    --target=$LFS_TGT         \
    --prefix=$LFS/tools       \
    --with-glibc-version=2.42 \
    --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
make install

3) Linux API Headers + Glibc + Libstdc++

이 구간은 의존성 순환을 끊는 핵심입니다. Glibc build 시 --host/--build 조합과 libc_cv_slibdir=/usr/lib 누락 여부를 반드시 확인해야 합니다.

# Glibc build 디렉토리에서
echo "rootsbindir=/usr/sbin" > configparms

../configure                             \
      --prefix=/usr                      \
      --host=$LFS_TGT                    \
      --build=$(../scripts/config.guess) \
      --disable-nscd                     \
      libc_cv_slibdir=/usr/lib           \
      --enable-kernel=5.4
# Libstdc++ (GCC 소스 내부 libstdc++-v3)
../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++/15.2.0
make
make DESTDIR=$LFS install

4) Chapter 5 종료 전 sanity check (필수)

echo 'int main(){}' | $LFS_TGT-gcc -x c - -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
grep -E -o "$LFS/lib.*/S?crt[1in].*succeeded" dummy.log
grep -B3 "^ $LFS/usr/include" dummy.log
grep 'SEARCH.*/usr/lib' dummy.log | sed 's|; |\n|g'
grep "/lib.*/libc.so.6 " dummy.log
grep found dummy.log
검증 항목정상 상태비정상 징후조치
ELF 인터프리터/lib64/ld-linux-*.so.* 형태/mnt/lfs 경로가 직접 노출Glibc/링커 설정 재검토
CRT 파일$LFS/lib ... Scrt1.o/crti.o/crtn.o succeededhost 경로 우선 탐색sysroot/headers 경로 재설정
헤더 검색$LFS/tools/.../include + $LFS/usr/include/usr/include 단독 우선PATH/LFS_TGT 점검
libc 해석attempt to open $LFS/usr/lib/libc.so.6 succeededhost libc 선택Glibc install/ld 설정 재실행

Chapter 6 임시 도구 Cross Compile 런북

Chapter 6은 "Cross toolchain으로 기본 유틸리티를 최종 위치에 설치"하는 단계입니다. 아직 host 독립은 아니며(책 원문 표현 그대로), Chroot 전에 필요한 사용자 공간 기반을 만듭니다.

핵심 패턴

Binutils Pass 2 (핵심 차이점)

../configure                   \
    --prefix=/usr              \
    --build=$(../config.guess) \
    --host=$LFS_TGT            \
    --disable-nls              \
    --enable-shared            \
    --enable-gprofng=no        \
    --disable-werror           \
    --enable-64-bit-bfd        \
    --enable-new-dtags         \
    --enable-default-hash-style=gnu
make
make DESTDIR=$LFS install
rm -v $LFS/usr/lib/lib{bfd,ctf,ctf-nobfd,opcodes,sframe}.{a,la}

GCC Pass 2 (실패 빈도 높은 옵션)

../configure                   \
    --build=$(../config.guess) \
    --host=$LFS_TGT            \
    --target=$LFS_TGT          \
    --prefix=/usr              \
    --with-build-sysroot=$LFS  \
    --enable-default-pie       \
    --enable-default-ssp       \
    --disable-nls              \
    --disable-multilib         \
    --disable-libatomic        \
    --disable-libgomp          \
    --disable-libquadmath      \
    --disable-libsanitizer     \
    --disable-libssp           \
    --disable-libvtv           \
    --enable-languages=c,c++   \
    LDFLAGS_FOR_TARGET=-L$PWD/$LFS_TGT/libgcc
실전 경고: --with-build-sysroot=$LFS 또는 LDFLAGS_FOR_TARGET=-L$PWD/$LFS_TGT/libgcc 누락 시, Pass 2에서 C++ 예외 처리/링크 오류가 자주 발생합니다.

Chapter 7 전환: Chroot 진입 품질 게이트

Chroot 진입은 단순 명령 1줄이 아니라 "Cross build 종료 선언"입니다. 진입 후 /tools/bin이 PATH에서 사라져야 하며, 이후는 네이티브 빌드 단계로 이동합니다.

# 가상 파일시스템 마운트 (대표 예시)
mount -v --bind /dev  $LFS/dev
mount -vt devpts devpts -o gid=5,mode=0620 $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run
# stable-systemd Chapter 7 진입 명령
chroot "$LFS" /usr/bin/env -i   \
    HOME=/root                  \
    TERM="$TERM"                \
    PS1='(lfs chroot) \u:\w\$ ' \
    PATH=/usr/bin:/usr/sbin     \
    MAKEFLAGS="-j$(nproc)"      \
    TESTSUITEFLAGS="-j$(nproc)" \
    /bin/bash --login

진입 직후 검증

echo "$PATH"
which gcc
which ld
ls -l /tools || true
test -x /usr/bin/gcc && echo "native gcc ready"
echo 'int main(){}' > t.c && gcc t.c -o t && ./t; echo $?
rm -f t.c t

Cross Build 의사결정 매트릭스

증상가장 먼저 볼 것2차 확인복구 범위
cannot find crt1.ogrep -E -o ...crt... dummy.log$LFS/usr/lib 설치 상태Glibc 재설치 후 sanity check 재실행
cannot find -lcgrep \"/lib.*/libc.so.6 \" dummy.loglibc.so.6 실제 위치Glibc 빌드 단계 재시작
host 헤더 참조grep -B3 \"^ $LFS/usr/include\" dummy.logPATH/LFS_TGTPass 1 GCC~Glibc 구간 재빌드
Pass 2 C++ 링크 실패--with-build-sysroot 확인LDFLAGS_FOR_TARGET 확인GCC Pass 2 재빌드
Chroot 진입 후 명령 이상/proc,/sys,/dev,/run 마운트PATH에 /tools/bin 포함 여부마운트 재구성 후 재진입

Cross Build 복구 런북 (빠른 재시작)

오염이 의심되면 부분 수정보다 "안전한 재시작"이 총 시간을 줄입니다.

  1. 현재 셸 상태 보존: 실패 로그 백업 (config.log, dummy.log, 빌드 스크립트)
  2. 마운트 정리: Chroot 관련 마운트 역순 해제
  3. 작업 디렉토리 초기화: 실패 패키지의 build 디렉토리 완전 삭제 후 재추출
  4. 환경 재확정: LFS/LFS_TGT/PATH/LC_ALL 재검증
  5. 최소 단위 재실행: 실패 지점의 바로 앞 패키지부터 재실행
# 예시: Chroot 종료 후 안전 언마운트
mountpoint -q $LFS/dev/shm && umount $LFS/dev/shm
umount -v $LFS/dev/pts
umount -v $LFS/{sys,proc,run,dev}

# 실패 패키지 재시작 예시
cd $LFS/sources
rm -rf gcc-15.2.0 build
tar -xf gcc-15.2.0.tar.xz
cd gcc-15.2.0
# 이후 책의 해당 장 커맨드 순서대로 재실행
LFS Cross Build 품질 게이트 — Chapter 5/6/7 전환 시 검증 우선 전략 LFS Cross Build 품질 게이트 — Chapter 5/6/7 전환 시 검증 우선 전략 게이트 통과 전에는 다음 Phase로 진행하지 않는다 · 실패하면 이전 Phase로 복구한 뒤 게이트를 재통과한다 Phase 1 Cross Toolchain Ch.5 PASS Gate A FAIL Phase 2 임시 도구 + Pass 2 Ch.6 PASS Gate B FAIL Phase 3 네이티브 빌드 Ch.7+ · 최종 시스템 PASS 실패 → Ch.5 문제 패키지 재빌드 후 재검증 실패 → 마운트/환경 재검증 후 재진입 Gate A — dummy.log sanity check · Ch.5 종료 전 필수 1. ELF 인터프리터 → /lib64/ld-linux-*.so.* 형태 확인 2. CRT 파일 → Scrt1.o/crti.o/crtn.o succeeded 확인 3. 헤더 검색 → $LFS/tools/include + $LFS/usr/include 4. libc 해석 → $LFS/usr/lib/libc.so.6 succeeded 실패 시 조치: 문제 패키지부터 Ch.5 재빌드 → sanity check 재실행 Gate B — Chroot 진입 즉시 검증 · /tools 비활성 + PATH 1. PATH → /tools/bin 미포함 확인 (echo $PATH) 2. gcc/ld → /usr/bin 해상도 (which gcc, which ld) 3. /tools → 더 이상 사용하지 않음 (ls -l /tools) 4. 테스트 빌드 → gcc t.c -o t && ./t 성공 실패 시 조치: 가상 파일시스템 재마운트 + 환경 재검증 후 재진입
Cross build 품질 게이트 — Chapter 5/6/7 전환 시 검증 우선 전략

크로스 빌드 트러블슈팅

LFS 빌드 과정에서 발생하는 흔한 오류와 해결 방법을 정리합니다. 대부분의 문제는 환경 변수 누락, 잘못된 도구 사용, 빌드 순서 위반에서 비롯됩니다.

흔한 에러와 해결 방법

증상원인해결
cannot find -lgcc 크로스 컴파일러의 libgcc를 찾지 못함 $LFS/tools/lib/gcc/$LFS_TGT/15.2.0/에 libgcc.a 존재 확인
undefined reference to __stack_chk_fail SSP(Stack Smashing Protector) 라이브러리 미설치 Glibc 빌드가 성공했는지 확인. $LFS/usr/lib/libc.so 존재 확인
wrong ELF class: ELFCLASS64 32비트/64비트 라이브러리 혼합 --disable-multilib 확인. 호스트의 32비트 라이브러리가 섞인 것
error: C compiler cannot create executables 컴파일러 또는 링커 경로 문제 $PATH에 $LFS/tools/bin이 포함되었는지 확인
configure: error: cannot run C compiled programs 크로스 컴파일된 바이너리를 호스트에서 실행 시도 --host와 --build 옵션이 올바른지 확인
Sanity check: 잘못된 동적 링커 경로 sysroot 설정 오류 Binutils와 GCC의 --with-sysroot=$LFS 확인
No such file or directory (chroot 진입 시) 가상 파일시스템 미마운트 또는 bash 미설치 /proc, /sys, /dev 마운트 확인. $LFS/usr/bin/bash 확인
프로그램이 호스트의 libc에 링크됨 --host=$LFS_TGT 누락 configure에 --host=$LFS_TGT 옵션 추가
error: 'SIGSTKSZ' was not declared Glibc 2.34+ 변경사항 (SIGSTKSZ가 더 이상 상수가 아님) 해당 패키지의 LFS 패치 적용
make 병렬 빌드 실패 의존성 순서가 보장되지 않는 Makefile make -j1로 단일 스레드 빌드 시도

진단 명령어

# 1. 바이너리의 타겟 아키텍처 확인
file /path/to/binary
# 기대: ELF 64-bit LSB executable, x86-64, ...

# 2. ELF 헤더 상세 확인 (아키텍처, OS/ABI)
readelf -h /path/to/binary
# Machine: Advanced Micro Devices X86-64
# OS/ABI: UNIX - GNU

# 3. 동적 링커 및 공유 라이브러리 확인
readelf -l /path/to/binary | grep interpreter
# [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

# 4. 공유 라이브러리 의존성 확인
readelf -d /path/to/binary | grep NEEDED
# 또는 (Chroot 안에서)
ldd /path/to/binary

# 5. 크로스 컴파일러의 검색 경로 확인
$LFS_TGT-gcc -print-search-dirs
$LFS_TGT-gcc -print-sysroot

# 6. 특정 라이브러리가 어디에 있는지 확인
$LFS_TGT-gcc -print-file-name=libc.so
$LFS_TGT-gcc -print-file-name=crt1.o

# 7. 헤더 파일 검색 경로
$LFS_TGT-gcc -E -Wp,-v -xc /dev/null 2>&1 | grep '^ '

# 8. RPATH 확인
readelf -d /path/to/binary | grep -E 'RPATH|RUNPATH'
절대로 호스트의 /usr/lib 라이브러리를 사용하지 마세요! LFS 바이너리가 호스트의 라이브러리에 링크되면, 호스트 없이는 LFS 시스템이 동작하지 않습니다. 항상 readelf -l로 동적 링커 경로를 확인하고, readelf -d로 NEEDED 라이브러리가 $LFS 안에 있는지 검증하세요.

빌드 환경 완전 초기화

# 심각한 문제가 발생했을 때 처음부터 다시 시작
# 주의: 모든 빌드 결과가 삭제됩니다!

# 1. Chroot 해제 (안에 있다면)
exit

# 2. 가상 파일시스템 언마운트
mountpoint -q $LFS/dev/shm && umount $LFS/dev/shm
umount $LFS/dev/pts
umount $LFS/{sys,proc,run,dev}

# 3. LFS 파티션 내용 삭제 (주의!)
rm -rf $LFS/*

# 4. 필수 디렉토리 재생성
mkdir -pv $LFS/{etc,var} $LFS/usr/{bin,lib,sbin}
for i in bin lib sbin; do ln -sv usr/$i $LFS/$i; done
case $(uname -m) in x86_64) mkdir -pv $LFS/lib64 ;; esac
mkdir -pv $LFS/tools
mkdir -v $LFS/sources
chmod -v a+wt $LFS/sources

# 5. Pass 1부터 다시 시작

BLFS 확장 가이드

LFS로 기본 시스템을 완성한 후, BLFS(Beyond Linux From Scratch)를 통해 실용적인 데스크톱/서버 시스템으로 확장할 수 있습니다. BLFS는 LFS 위에 그래픽, 네트워크, 멀티미디어 등을 추가하는 가이드입니다.

LFS → BLFS 확장 경로 — 기본 시스템에서 데스크톱/서버 시스템까지의 확장 단계 LFS → BLFS 확장 경로 기본 시스템 위에 BLFS 확장 패키지를 쌓아 데스크톱/서버 시스템을 완성하는 단계 1단계 2단계 3단계 LFS 기본 시스템 (81 패키지) 커널 · glibc · binutils · GCC · bash — 부팅 가능한 최소 시스템 보안 & 네트워크 OpenSSH · Wget · cURL GnuTLS · NSS · p11-kit Linux-PAM · sudo · Polkit iptables · WireGuard 그래픽 & 데스크톱 Xorg · Wayland · libinput Mesa (OpenGL · Vulkan) GTK+4 · Qt6 · Cairo · Pango FreeType · Fontconfig · HarfBuzz 서버 & 개발 Apache/Nginx · MariaDB PostgreSQL · PHP · Node.js Git · CMake · LLVM/Clang Rust · Go · Java (OpenJDK) 데스크톱 시스템 GNOME · KDE · Xfce 중 택 1 그래픽 · 보안/네트워크 확장 LFS 81 + BLFS 200~400 패키지 서버 시스템 웹 서버 · DB · 개발 도구 서버/개발 · 보안/네트워크 확장 LFS 81 + BLFS 50~100 패키지 예상 빌드 시간: LFS 약 50 SBU + BLFS 데스크톱 약 300 SBU · 서버 약 100 SBU → 전체 약 2~5일 (하드웨어 성능 의존)
LFS → BLFS 확장 경로 — 기본 시스템에서 데스크톱/서버까지의 확장 단계

BLFS 필수 패키지 (서버용)

카테고리패키지용도
보안OpenSSH, sudo, Linux-PAM원격 접속, 권한 관리
네트워크Wget, cURL, rsync파일 전송, 동기화
암호화GnuTLS, NSS, p11-kitTLS/SSL, 인증서 관리
편의Git, tmux, htop버전 관리, 터미널 분할, 모니터링

BLFS 필수 패키지 (데스크톱용)

카테고리패키지용도
그래픽 기반Xorg, Mesa, libinput디스플레이 서버, 3D 가속, 입력 장치
툴킷GTK+4, Qt6, CairoGUI 애플리케이션(Application) 프레임워크
폰트FreeType, Fontconfig, HarfBuzz글꼴 렌더링, 관리
데스크톱GNOME, KDE, Xfce 중 택 1데스크톱 환경
멀티미디어ALSA, PulseAudio/PipeWire, FFmpeg오디오, 비디오
브라우저Firefox, Chromium웹 브라우저 (빌드에 매우 오래 걸림)

보안 강화 (Hardened LFS)

LFS의 큰 장점 중 하나는 보안 설정을 완전히 제어할 수 있는 것입니다. 아래는 LFS 시스템의 보안을 강화하는 주요 기법들입니다.

컴파일러 수준 보안

기법GCC 옵션설명LFS 기본값
PIE-fPIE -piePosition Independent Executable — ASLR 활성화--enable-default-pie (활성)
SSP-fstack-protector-strong스택 버퍼 오버플로우 탐지 (canary)--enable-default-ssp (활성)
FORTIFY-D_FORTIFY_SOURCE=2버퍼 오버플로우 런타임 검사수동 설정 필요
RELRO-Wl,-z,relro,-z,nowGOT 테이블 보호 (Full RELRO)수동 설정 필요
NX(기본 활성)실행 불가능 스택 (No eXecute)커널 + GCC 기본 활성
전역 보안 플래그 설정: LFS 시스템 전체에 보안 플래그를 적용하려면 /etc/profile이나 별도의 환경 설정에 추가합니다:
# /etc/profile.d/hardening.sh
export CFLAGS="-O2 -pipe -D_FORTIFY_SOURCE=2 -fstack-protector-strong"
export CXXFLAGS="$CFLAGS"
export LDFLAGS="-Wl,-z,relro,-z,now"

커널 수준 보안

설정옵션설명
ASLRkernel.randomize_va_space=2주소 공간(Address Space) 배치 랜덤화 (Full ASLR)
dmesg 제한kernel.dmesg_restrict=1비특권 사용자의 커널 로그 접근 제한
kptr 제한kernel.kptr_restrict=2커널 포인터 주소 노출 방지
ptrace 제한kernel.yama.ptrace_scope=1자식 프로세스만 ptrace 허용
SYN 쿠키net.ipv4.tcp_syncookies=1SYN Flood 공격 방지
# /etc/sysctl.d/99-hardening.conf
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
kernel.yama.ptrace_scope = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

흔한 실수와 해결

LFS 빌드 과정에서 자주 발생하는 실수와 해결 방법을 정리합니다. 대부분의 실패는 사소한 실수에서 비롯되며, 아래 체크리스트로 사전에 방지할 수 있습니다.

LFS 빌드 흔한 실수 분류 및 빈도 LFS 빌드 흔한 실수 분류 및 빈도 40% 25% 20% 15% 환경 변수 실수 빌드 순서 오류 호스트 오염 부팅 실패 빈도: 전체 실수 대비 비중 (합계 100%) 환경 변수 실수 40% • $LFS 미설정/오타 • $LFS_TGT 미설정 • $PATH 순서 오류 • LC_ALL=POSIX 누락 • 재부팅 후 환경 초기화 해결: .bashrc 확인 echo $LFS 로 항상 검증 작업 시작 전 export 재실행 빌드 순서 오류 25% • 패키지 순서 건너뜀 • Pass 1/2 순서 착각 • Sanity Check 스킵 • 소스 디렉토리 미정리 • DESTDIR=$LFS 누락 해결: LFS 책 순서 엄수 Sanity Check 절대 스킵 금지 rm -rf build/ 후 재빌드 호스트 오염 20% • --host=$LFS_TGT 누락 • 호스트 /usr/lib 링크 • /bin/sh → dash 미수정 • 호스트 pkg-config 간섭 • LD_LIBRARY_PATH 오염 해결: readelf -l 로 확인 동적 링커 경로 검증 ldd 로 링크 라이브러리 확인 부팅 실패 15% • 커널 CONFIG 누락 (devtmpfs) • GRUB root= 파티션 오류 • /etc/fstab UUID 불일치 • 디스크 컨트롤러 드라이버 누락 • 파일시스템 드라이버 모듈화 해결: 필수 옵션 =y 확인 blkid로 UUID 확인 ext4, AHCI/NVMe는 =y 내장
LFS 빌드 흔한 실수 분류 및 빈도 — 상단 스택 바의 구간 길이가 빈도 비중(합계 100%)을 나타내며, 환경 변수 실수가 40%로 가장 빈번합니다.

자주 묻는 질문 (FAQ)

질문답변
LFS를 빌드하는 데 얼마나 걸리나요? 최신 8코어 시스템에서 약 6~12시간. 옛날 시스템이면 2~3일. -j$(nproc) 병렬 빌드가 핵심입니다.
빌드 중 전원이 꺼지면? $LFS 마운트 상태 확인 후 마지막으로 성공한 패키지 다음부터 재개하면 됩니다. VM 스냅샷이 가장 안전합니다.
64비트와 32비트를 동시에 지원하려면? Multilib LFS를 참조하세요. --enable-multilib으로 GCC를 빌드하고, 32비트 Glibc도 별도 빌드합니다.
LFS 시스템에서 패키지를 업데이트하려면? 새 버전의 소스를 다운로드하고 같은 절차로 재빌드합니다. DESTDIR 아카이브 전략 사용 시 이전 버전 롤백(Rollback)도 가능합니다.
ARM이나 RISC-V에서 LFS를 빌드할 수 있나요? CLFS(Cross LFS) 프로젝트를 참조하세요. 실제 크로스 컴파일로 다른 아키텍처용 시스템을 빌드합니다.
LFS는 실무에서 사용할 수 있나요? 교육/학습 목적이 주이지만, 임베디드 시스템이나 특수 용도 어플라이언스에서 실제 사용되기도 합니다. 보안 업데이트를 직접 관리해야 하므로 프로덕션 서버에는 권장하지 않습니다.

요약 및 참고 자료

핵심 개념 요약

LFS 학습 로드맵 — 사전 학습부터 자체 배포판 제작까지의 단계별 경로 LFS 학습 로드맵 1 사전 학습 리눅스 CLI 기초 GCC/Make 기본 사용법 성과: 개발 도구 자유 활용 2 LFS 빌드 소스에서 시스템 빌드 크로스 컴파일 이해 성과: 최소 리눅스 구축 3 BLFS 확장 데스크톱/서버 구축 패키지 의존성 관리 성과: 앱 환경까지 구축 4 고급 과정 커널 커스터마이징 패키지 매니저 구축 성과: 커널·패키지 제어 5 배포판 제작 자체 배포판 구축 임베디드 시스템 성과: 자체 배포판 완성 숙련도 초급 중급 중상급 고급 전문가 ↑ 관련 학습 자료 (이 사이트) GCC 컴파일러 빌드 시스템 Binutils ELF 부팅 과정 Systemd 네트워킹 커널 컴파일 디바이스 드라이버 파일시스템 메모리 관리 프로세스 관리
LFS 학습 로드맵 — 사전 학습부터 자체 배포판 제작까지의 단계별 경로

공식 문서 및 프로젝트

커뮤니티 및 지원

GNU 툴체인 및 핵심 소프트웨어 문서

리눅스 커널 및 시스템 표준 문서

Init 시스템 및 부트로더

패키지 관리 및 확장 참고

참고 서적

서적저자설명
Linux From ScratchGerard Beekmans 외LFS 공식 책 (무료 온라인)
Advanced Linux ProgrammingMark Mitchell 외리눅스 시스템 프로그래밍 기초
Understanding the Linux KernelDaniel P. Bovet, Marco Cesati커널 내부 구조
Linux System ProgrammingRobert Love시스템 콜, 파일 I/O, 프로세스
The Linux Command LineWilliam ShottsCLI 기초 (무료 온라인), LFS 사전 학습에 적합
Embedded Linux PrimerChristopher Hallinan임베디드 리눅스 구축 (LFS 확장 응용)
How Linux WorksBrian Ward리눅스 시스템 동작 원리 개론

유용한 도구 및 스크립트

도구설명URL
jhalfsLFS 빌드 자동화 스크립트 (ALFS 프로젝트)linuxfromscratch.org/alfs/
version-check.sh호스트 요구사항 검증 스크립트 (LFS 책에 포함)LFS Book Chapter 2
copy-kernel-config호스트 커널 설정을 기반으로 LFS 커널 설정 생성zcat /proc/config.gz > .config
porg소스 빌드 패키지 추적 도구 (LD_PRELOAD 기반)porg.sourceforge.net
fakeroot비특권 사용자로 패키지 빌드 시 root 소유 파일 생성 시뮬레이션BLFS에서 설치
필수 관련 문서: