Linux From Scratch (LFS) 종합 가이드

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

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

핵심 요약

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

단계별 요약

LFS 빌드는 크게 4단계로 진행됩니다:

  1. 1단계: 호스트 준비 — 호스트 시스템 요구사항 확인, LFS 파티션 생성 및 마운트, lfs 사용자 생성, 환경 변수 설정
  2. 2단계: 크로스 툴체인 구축 — Binutils Pass 1 → GCC Pass 1 → Linux API 헤더 → Glibc → Libstdc++ 순서로 크로스 컴파일러 구축
  3. 3단계: 임시 도구 크로스 컴파일 — 크로스 컴파일러로 m4, ncurses, bash 등 기본 유틸리티를 $LFS에 설치, 이어서 Binutils/GCC Pass 2로 네이티브 컴파일러 구축
  4. 4단계: Chroot → 최종 시스템 — Chroot 환경 진입 후 81개 패키지를 최종 빌드, 커널 컴파일, GRUB 설정, systemd 구성으로 부팅 가능 시스템 완성

LFS 개요와 철학

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

왜 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배 시간이 걸린다는 의미입니다. 실제 시간은 하드웨어에 따라 크게 다르며, 최신 멀티코어 시스템에서 1 SBU는 보통 0.5~2분입니다.
항목LFS 12.4-systemd
릴리스 날짜2024년 9월
리눅스 커널6.10.x
GCC14.2.0
Glibc2.40
Binutils2.43.1
init 시스템systemd 256
총 패키지 수81개 + 패치
예상 빌드 시간약 30~50 SBU (하드웨어에 따라 상이)
필요 디스크 공간최소 30GB (소스 + 빌드)
LFS 전체 빌드 프로세스 7단계 플로우 1단계 호스트 준비 2단계 파티션 설정 3단계 크로스 툴체인 4단계 임시 도구 5단계 Chroot 진입 6단계 시스템 빌드 7단계 부팅 설정 Ch.2 Ch.2-4 Ch.5 Ch.6 Ch.7 Ch.8 Ch.9-11 LFS 전체 빌드 프로세스 호스트 준비부터 부팅 가능 시스템까지 7단계 크로스 컴파일 영역 네이티브 빌드 영역
그림 1. LFS 전체 빌드 프로세스 7단계 — 호스트 준비부터 부팅 가능 시스템까지
LFS vs 일반 배포판 비교 LFS (Linux From Scratch) ✓ 소스에서 직접 빌드 ✓ 81개 핵심 패키지만 포함 ✓ 완전한 커스터마이징 ✓ 시스템 내부 구조 학습 ✓ 패키지 매니저 없음 (직접 관리) ✓ 최소 디스크 사용 (~500MB) ✗ 빌드에 수 시간~수일 소요 ✗ 업데이트 수동 관리 ✗ 높은 진입 장벽 일반 배포판 (Ubuntu 등) ✓ 사전 빌드 바이너리 패키지 ✓ 수만 개 패키지 저장소 ✓ apt/dnf 패키지 매니저 ✓ 빠른 설치 (10~30분) ✓ 자동 업데이트 ✓ 커뮤니티 지원 ✗ 불필요한 패키지 다수 포함 ✗ 내부 구조 이해 어려움 ✗ 커스터마이징 한계
그림 12. LFS vs 일반 배포판 비교 — 직접 빌드의 장단점

LFS 버전 변천사

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

시기버전주요 변화
1999LFS 1.0Gerard Beekmans가 프로젝트 시작, 최초의 "소스에서 빌드" 가이드
2002LFS 4.0패키지 수 40개 이상, 안정적 빌드 절차 확립
2005LFS 6.0Udev 도입, 2.6 커널 기반, 빌드 절차 대폭 개선
2007LFS 6.3크로스 컴파일 방식 도입 시작 (호스트 격리 강화)
2012LFS 7.0/tools → /usr 통합 시작, Systemd 에디션 분리
2015LFS 7.7Systemd 에디션 공식화, SysVinit 에디션과 병행
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
2024LFS 12.2GCC 14.2, Glibc 2.40, 커널 6.10, systemd 256
LFS 버전 타임라인 LFS 주요 버전 타임라인 (1999~2024) 1.0 1999 프로젝트 시작 6.0 2005 Udev 도입 7.0 2012 Systemd 분리 9.0 2019 Python 3 필수 11.0 2021 /usr 병합 12.2 2024 GCC 14, 커널 6.10 초기 확립기 현대화 (Systemd, Cross Compile) /usr 병합 시대
그림 14. LFS 주요 버전 타임라인 — 1999년 시작부터 2024년 LFS 12.2까지의 주요 이정표

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 디렉토리 트리 구조 (빌드 완료 후) / ($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 systemd/, locale.conf /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 — 소스 타르볼 저장소. 빌드 완료 후 삭제하여 디스크 절약
그림 15. $LFS 디렉토리 트리 구조 — /usr 병합 이후의 FHS 호환 레이아웃

가상머신 실습 환경 구성

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

도구추천 설정장점
VirtualBoxRAM 4GB+, 디스크 50GB (동적 할당), Ubuntu/Debian 호스트무료, 스냅샷, 공유 폴더
QEMU/KVMRAM 4GB+, virtio 디스크 50GB, virt-manager GUI고성능, 리눅스 네이티브, 자유도 높음
VMware WorkstationRAM 4GB+, 디스크 50GB, 스냅샷 활용안정성, 스냅샷 관리 편리
WSL2 (Windows)Ubuntu 22.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 22.04+, Fedora 38+, Debian 12+)이 요구사항을 충족합니다.

필수 패키지 및 최소 버전

패키지최소 버전확인 명령용도
Bash3.2+bash --version셸 스크립트 실행
Binutils2.13.1+ld --version어셈블러, 링커
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.2+gcc --versionC/C++ 컴파일러
Glibc2.11+ldd --versionC 라이브러리
Grep2.5.1a+grep --version패턴 검색
Gzip1.3.12+gzip --version압축
Linux Kernel4.19+uname -r호스트 커널
M41.4.10+m4 --version매크로 프로세서
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 전용 문법을 사용합니다.

version-check.sh 스크립트

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

#!/bin/bash
# LFS 12.4 호스트 요구사항 검증 스크립트

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

파티션 및 파일시스템 준비

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

추천 파티션 구성

마운트 포인트파일시스템최소 크기권장 크기설명
/ (루트)ext410 GB30 GBLFS 시스템 전체 (소스 + 빌드)
/bootext2200 MB500 MB커널, GRUB (선택)
swapswapRAM과 동일RAM × 2스왑 영역
/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/lfsmount 명령을 다시 실행하세요. /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 (해시 비활성화): Bash는 실행 파일 경로를 해시 테이블에 캐시합니다. 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 Machine x86_64-pc-linux-gnu 컴파일을 수행하는 머신 호스트 GCC 실행 make & configure 실행 Host Machine x86_64-lfs-linux-gnu 빌드된 프로그램이 실행될 머신 빌드 결과물 실행 $LFS 파티션 = 미래 시스템 Target Machine x86_64-lfs-linux-gnu 생성된 코드가 실행될 머신 컴파일러에만 해당 GCC/Binutils 빌드 시만 사용 실행 파일 생성 코드
그림 2. Build/Host/Target 세 머신의 관계 — Build에서 컴파일, Host에서 실행, Target은 컴파일러가 생성하는 코드의 실행 환경

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

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

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

툴체인 기술 분석

툴체인(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번째
크로스 컴파일 3단계 파이프라인 크로스 컴파일 파이프라인 소스 (.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 (라이브러리)
그림 4. 크로스 컴파일 파이프라인 — 모든 도구가 $LFS_TGT- 접두사를 사용하며 Sysroot에서 헤더/라이브러리를 참조
툴체인 의존성 순환(libgcc↔glibc) 해결 의존성 순환 문제와 해결 문제: 순환 의존성 GCC (libgcc) Glibc glibc 필요 libgcc 필요 GCC는 glibc 헤더가 필요하고 Glibc는 libgcc가 필요 → 교착! 해결: 단계적 빌드 1. GCC Pass 1 (제한적) 2. Linux Headers 3. Glibc (완전 빌드) 4. Libstdc++ --with-newlib --without-headers libgcc_eh 대신 libgcc_s 사용 (inhibit_libc로 우회)
그림 5. 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 디렉토리 구조 Sysroot ($LFS) 디렉토리 구조 $LFS (/mnt/lfs) tools/ usr/ sources/ etc/ bin/ lib/ $LFS_TGT-gcc $LFS_TGT-ld libgcc.a libstdc++.a include/ lib/ bin/ linux/ (커널 헤더) stdio.h (glibc) libc.so crt1.o bash ls, cat... ■ tools/ — 크로스 컴파일러 설치 위치 (호스트에서 실행되는 도구) ■ usr/ — 타겟 시스템의 라이브러리·헤더·유틸리티 (Sysroot 역할) ■ sources/ — 소스 타르볼 저장소
그림 6. 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/14.2.0/include
# 3. $LFS/tools/lib/gcc/$LFS_TGT/14.2.0/include-fixed

# 라이브러리 검색 순서
# 1. $LFS/usr/lib
# 2. $LFS/lib
# 3. $LFS/tools/lib
크로스 툴체인 빌드 순서 총정리 크로스 툴체인 빌드 순서 총정리 (Chapter 5) 1. Binutils Pass 1 as, ld 크로스 빌드 → $LFS/tools/bin/ 2. GCC Pass 1 --with-newlib (제한적) glibc 없이 컴파일러 생성 3. Linux API 헤더 make headers → $LFS/usr/include/ 4. Glibc libc.so, ld-linux.so 순환 의존성 해결! 5. Libstdc++ C++ 표준 라이브러리 Glibc 위에 빌드 핵심 의존성 관계 Binutils → GCC가 as/ld 사용 | GCC Pass 1 → --with-newlib로 glibc 없이 빌드 | Linux 헤더 → Glibc가 syscall 번호 참조 | Glibc → Libstdc++가 libc.so 링크 필수! Glibc 후 Sanity Check echo 'int main(){}' | $LFS_TGT-gcc -xc - readelf -l a.out | grep ld-linux Chapter 6: 임시 도구 크로스 컴파일 m4, ncurses, bash, coreutils... → $LFS/usr/ 에 설치
그림 20. 크로스 툴체인 빌드 순서 총정리 — 5단계 빌드와 의존성 관계, Sanity Check 시점

Binutils Pass 1

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

왜 Binutils가 먼저인가? GCC의 configure는 링커(ld)가 지원하는 기능(예: --hash-style=gnu)을 테스트합니다. Binutils가 없으면 GCC configure가 기능 감지에 실패하여 최적화되지 않은 설정이 적용됩니다.

빌드 절차

# 소스 압축 해제 및 빌드 디렉토리 생성
cd $LFS/sources
tar -xf binutils-2.43.1.tar.xz
cd binutils-2.43.1
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 프로파일링 도구 비활성화. 크로스 빌드 시 불필요
--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-14.2.0.tar.xz
cd gcc-14.2.0

# 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에서 라이브러리 디렉토리를 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.40            \
    --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.40타겟 glibc 버전을 지정 (호환성 헤더 생성용)
--with-sysroot=$LFSsysroot를 $LFS로 설정하여 타겟 헤더/라이브러리 경로 지정
--with-newlibinhibit_libc 정의 — glibc 없이 빌드 가능하게 함
--without-headers시스템 헤더 없이 빌드. 커널 헤더가 아직 없으므로 필수
--enable-default-piePosition-Independent Executable을 기본값으로. ASLR 보안 강화
--enable-default-sspStack Smashing Protector를 기본 활성화. 스택 버퍼 오버플로 방지
--disable-shared정적 라이브러리만 빌드. 크로스 컴파일 시 공유 라이브러리 문제 방지
--disable-multilib32비트 지원 비활성화. x86_64 전용
--disable-threads스레드 지원 비활성화. 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 커널은 사용자 공간 프로그램이 커널 서비스를 호출할 수 있도록 C 헤더 파일을 제공합니다. 이 헤더는 시스템 콜 번호, 구조체 정의, ioctl 명령 등을 포함하며, Glibc가 빌드될 때 이 헤더를 참조합니다.

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

빌드 절차

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

# 이전 빌드 아티팩트 제거
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, 소켓, 파일시스템 구조체 등
asm/아키텍처별 정의 (레지스터, 시그널 등)
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 내부 구성요소 Glibc 내부 구성요소 GNU C Library (Glibc 2.40) libc.so.6 printf, scanf, sprintf malloc, free, calloc open, read, write, close pthread_*, socket, mmap ld-linux-x86-64.so.2 동적 링커/로더 .so 파일 탐색/로드 심볼 해결 (lazy bind) ELF 프로그램 최초 실행 libm.so.6 sin, cos, sqrt exp, log, pow 수학 함수 라이브러리 libpthread NPTL (Native POSIX Thread Library) libc.so에 통합됨 C 런타임 시작 코드 crt1.o — _start 진입점 crti.o — .init/.fini prologue crtn.o — .init/.fini epilogue Scrt1.o — PIE용 _start NSS (Name Service Switch) libnss_files, libnss_dns, libnss_compat 로케일 데이터 locale-archive, charmap libresolv DNS 해석, /etc/resolv.conf libdl / librt dlopen, clock_gettime iconv / gconv 문자 인코딩 변환 Glibc가 제공하는 것 = 사용자 프로그램이 커널과 소통하는 모든 인터페이스 syscall 래퍼 (write → 커널 sys_write) | POSIX API | C 표준 라이브러리 | 동적 링커 | 스레드 | 로케일 | DNS Glibc 2.34+에서 libpthread, libdl, librt, libutil이 libc.so에 통합됨 (별도 링크 불필요)
그림 21. Glibc 내부 구성요소 — 동적 링커, C 표준 라이브러리, 런타임 시작 코드, NSS 등 핵심 구성

사전 준비

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

# 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-2.40-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=4.19                 \
    --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=4.19최소 커널 버전 지정. 4.19 이전 커널의 호환 코드를 제외하여 크기 축소
--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/14.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-14.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++/14.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.19매크로 프로세서표준 크로스 빌드
2Ncurses6.5터미널 라이브러리호스트용 tic 먼저 빌드
3Bash5.2.32Chroot에서 /bin/bash로 사용
4Coreutils9.5기본 유틸리티 (ls, cp, mv 등)표준 크로스 빌드
5Diffutils3.10파일 비교표준 크로스 빌드
6File5.45파일 타입 판별호스트용 file 먼저 빌드
7Findutils4.10.0파일 검색 (find, xargs)표준 크로스 빌드
8Gawk5.3.0텍스트 처리표준 크로스 빌드
9Grep3.11패턴 검색표준 크로스 빌드
10Gzip1.13압축표준 크로스 빌드
11Make4.4.1빌드 자동화표준 크로스 빌드
12Patch2.7.6패치 적용표준 크로스 빌드
13Sed4.9스트림 편집기표준 크로스 빌드
14Tar1.35아카이브표준 크로스 빌드
15Xz5.6.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.19.tar.xz
cd m4-1.4.19

./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.5.tar.gz
cd ncurses-6.5

# 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=/usrDESTDIR=$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 비교 Pass 1 (크로스 컴파일러) 실행 위치: 호스트 시스템 설치 경로: $LFS/tools/bin 도구 이름: $LFS_TGT-gcc, $LFS_TGT-ld 기능: 제한적 (--with-newlib) 공유 라이브러리: 없음 (--disable-shared) 스레드: 없음 (--disable-threads) 역할: Glibc + 임시 도구를 크로스 빌드 출력: LFS 타겟용 바이너리 생성 Pass 2 (네이티브 컴파일러) 실행 위치: LFS 시스템 (Chroot 안) 설치 경로: $LFS/usr/bin 도구 이름: gcc, ld (접두사 없음) 기능: 완전한 기능 (Glibc 사용 가능) 공유 라이브러리: 있음 (--enable-shared) 스레드: 있음 (POSIX threads) 역할: Chroot에서 최종 시스템 패키지 빌드 출력: 최종 시스템 바이너리 생성
그림 7. Pass 1 vs Pass 2 — Pass 1은 호스트에서 실행되는 크로스 컴파일러, Pass 2는 LFS에서 실행되는 네이티브 컴파일러

Binutils Pass 2

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

# 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-14.2.0.tar.xz
cd gcc-14.2.0

# MPFR, GMP, MPC 추출
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

# 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는 $LFS 디렉토리를 루트(/)로 변경하여, 마치 새로운 시스템에 로그인한 것처럼 동작합니다.

소유권 변경

# 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

가상 파일시스템 마운트

# 가상 커널 파일시스템 마운트
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 환경 구조 호스트 vs Chroot 환경 호스트 시스템 /usr/bin/gcc (호스트 GCC) /usr/lib/libc.so (호스트 glibc) /proc, /sys, /dev (커널 제공) $LFS = /mnt/lfs /mnt/lfs/usr/bin/gcc (LFS GCC, Pass 2) /mnt/lfs/usr/lib/libc.so (LFS glibc) /mnt/lfs/tools/ (크로스 도구) /mnt/lfs/sources/ (소스 타르볼) chroot Chroot 환경 (LFS 시스템) / = (구 $LFS) /usr/bin/gcc → LFS GCC /usr/lib/libc.so → LFS glibc /proc → 호스트 /proc (바인드 마운트) /sys → 호스트 /sys (바인드 마운트) /dev → 호스트 /dev (바인드 마운트) 호스트 파일시스템에 접근 불가! 호스트 라이브러리 오염 불가능! 독립적인 시스템으로 동작
그림 8. 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에서는 81개의 패키지를 최종 빌드합니다. 이 단계에서는 Pass 2에서 빌드한 네이티브 GCC를 사용하여 모든 패키지를 다시 빌드합니다.

주요 패키지 빌드 순서 의존성 주요 패키지 빌드 의존성 그래프 Linux Headers Glibc Binutils GCC Zlib Bzip2 Ncurses Readline Bash Coreutils Perl Python Util-linux Systemd D-Bus 화살표 방향: 의존 관계 (A→B = B는 A에 의존)
그림 9. 주요 패키지 빌드 의존성 — 패키지는 의존성 순서에 따라 빌드해야 함

일반 빌드 패턴

# 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 빌드 이후 시스템을 장기적으로 유지하는 데 가장 중요한 결정 중 하나입니다.

패키지 관리 전략 비교 LFS 패키지 관리 전략 — 난이도 vs 기능 비교 구현 난이도 → 기능 완성도 → Timestamp 기반 설치 전후 비교 DESTDIR 아카이브 tar.gz 패키징 Symlink (Stow) 별도 디렉토리 + 링크 Install 추적 LD_PRELOAD hook RPM/dpkg 완전한 패키지 매니저 ← LFS 공식 권장 전략
그림 16. 패키지 관리 전략 비교 — DESTDIR 아카이브가 난이도 대비 기능이 가장 균형 잡힌 전략

패키지 관리 전략 비교

전략방법장점단점
별도 디렉토리 설치 --prefix=/usr/pkg/<name>-<ver>로 설치 후 심볼릭 링크 깔끔한 분리, 쉬운 제거 복잡한 심볼릭 링크 관리
Symlink 스타일 Stow/GNU Stow로 심볼릭 링크 자동 관리 표준화된 도구 사용 Stow 의존성
Timestamp 기반 설치 전후 파일 타임스탬프 비교 구현 간단 동시 빌드 불가, 부정확할 수 있음
Install 추적 LD_PRELOADinstall() 시스템 콜 가로채기 정확한 파일 추적 구현 복잡
패키지 아카이브 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가 부팅 가능한지 여부를 결정하는 가장 중요한 단계 중 하나입니다.

커널 컴파일 과정 커널 컴파일 과정 소스 준비 make mrproper 설정 make menuconfig 컴파일 make 모듈 설치 make modules_install 커널 설치 cp bzImage /boot config 저장 cp .config /boot
그림 10. 커널 컴파일 과정 — 소스 준비부터 /boot 설치까지

빌드 절차

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

# 소스 클린
make mrproper

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

# 컴파일 (병렬 빌드)
make

# 모듈 설치
make modules_install

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

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

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

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

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로 내장하세요 (모듈이 아님).

GRUB 부트로더 설정

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

부팅 과정 LFS 부팅 과정 BIOS/UEFI 하드웨어 초기화 GRUB 커널 로드 + initramfs Linux Kernel 커널 초기화 systemd (PID 1) 서비스 시작 Login Prompt agetty + bash
그림 11. LFS 부팅 과정 — 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 12.4-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.10.5-lfs-12.4-systemd" {
    linux /boot/vmlinuz-6.10.5-lfs-12.4-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 12.4-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 # 오늘 로그

전체 패키지 목록

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

핵심 시스템 라이브러리

#패키지버전크기 (KB)설명
1Glibc2.4018,362GNU C 라이브러리
2Zlib1.3.11,478압축 라이브러리
3Bzip21.0.8792블록 정렬 압축
4Xz Utils5.6.21,692LZMA 압축
5Zstd1.5.62,251Zstandard 압축
6Readline8.2.132,994명령줄 편집 라이브러리
7Ncurses6.56,620터미널 라이브러리
8Libffi3.4.61,340Foreign Function Interface
9OpenSSL3.3.117,476암호화 라이브러리
10Expat2.6.2702XML 파서
11Libelf (elfutils)0.1919,148ELF 라이브러리
12Libpipeline1.5.71,024파이프라인 라이브러리

빌드 도구

#패키지버전크기 (KB)설명
13Binutils2.43.127,540어셈블러, 링커
14GCC14.2.090,424C/C++ 컴파일러
15GMP6.3.02,094다중 정밀도 수학
16MPFR4.2.11,490다중 정밀도 부동소수점
17MPC1.3.1756다중 정밀도 복소수
18Make4.4.12,300빌드 자동화
19Autoconf2.722,080configure 스크립트 생성기
20Automake1.171,620Makefile 생성기
21Libtool2.4.7996라이브러리 빌드 도구
22Pkgconf2.3.0534컴파일러 플래그 관리
23M41.4.191,617매크로 프로세서
24Bison3.8.22,752파서 생성기
25Flex2.6.41,386렉서 생성기

핵심 유틸리티

#패키지버전크기 (KB)설명
26Coreutils9.55,724ls, cp, mv 등 기본 유틸리티
27Bash5.2.3210,704Bourne-Again Shell
28Grep3.111,664패턴 검색
29Sed4.91,370스트림 편집기
30Gawk5.3.03,356텍스트 처리
31Findutils4.10.01,940파일 검색
32Diffutils3.101,584파일 비교
33Patch2.7.6766패치 적용
34Tar1.352,192아카이브
35Gzip1.13757압축
36File5.451,218파일 타입 판별

시스템 관리

#패키지버전크기 (KB)설명
37Util-linux2.40.28,582시스템 유틸리티 (mount, fdisk 등)
38Systemd256.414,228init 시스템, 서비스 관리
39D-Bus1.14.106,640IPC 메시지 버스
40Procps-ng4.0.44,820프로세스 유틸리티 (ps, top)
41Psmisc23.7412pstree, fuser, killall
42E2fsprogs1.47.19,444ext2/3/4 파일시스템 도구
43Shadow4.16.01,774패스워드, 사용자 관리
44Kmod33600커널 모듈 관리 (modprobe)
45Kbd2.6.41,764키보드 유틸리티
46Sysvinit3.10236init 호환 (사용 안 함, systemd 대체)
47Eudev--systemd-udevd로 대체

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

#패키지버전크기 (KB)설명
48Perl5.40.013,500스크립트 언어
49Python 33.12.520,160스크립트 언어
50XML::Parser (Perl)2.47240Perl XML 파서 모듈
51Intltool0.51.0159국제화 도구
52Gettext0.22.59,860다국어 지원
53Texinfo7.15,424문서 시스템
54Groff1.23.07,268텍스트 포맷터 (man 페이지)
55Man-DB2.12.11,914man 페이지 관리
56Man-pages6.9.12,156리눅스 man 페이지

네트워킹 및 보안

#패키지버전크기 (KB)설명
57Iproute26.10.0892네트워크 설정 (ip, ss)
58IPtables1.8.10709방화벽
59Libcap2.70181POSIX capabilities
60Acl2.3.2356접근 제어 리스트
61Attr2.5.2456확장 속성

기타 핵심 패키지

#패키지버전크기 (KB)설명
62Linux Kernel6.10.5141,820리눅스 커널
63GRUB2.126,524부트로더
64Less661380텍스트 뷰어
65Vim9.1.066016,752텍스트 에디터
66MarkupSafe2.1.532Python HTML 이스케이프
67Jinja23.1.4260Python 템플릿 엔진
68Wheel0.44.0100Python 패키지 포맷
69Setuptools72.2.02,684Python 빌드 시스템
70Meson1.5.12,268빌드 시스템
71Ninja1.12.1228빌드 러너
72Inetutils2.51,632네트워크 유틸리티 (hostname, ping)
73GDBM1.241,168데이터베이스 라이브러리
74Gperf3.11,060완벽 해시 함수 생성기
75Bc6.7.6460계산기
76Check0.15.2760C 유닛 테스트
77LFS-Bootscripts--SysV 전용 (systemd 대체)
78Linux-PAM--BLFS에서 설치
79Libxcrypt4.4.36610crypt 라이브러리
80Flit-core3.9.064Python 빌드 백엔드
81Mpc (lib)1.3.1756복소수 연산

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 재시작
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 이후에 랜덤하게 깨지므로, 빌드 성공보다 경로/링크/동적 로더 검증이 더 중요합니다.

stable-systemd 버전 동기화 포인트

LFS stable-systemd 인덱스(Version 12.4-systemd) 기준으로 Cross build에 직접 영향을 주는 주요 버전은 다음과 같습니다.

컴포넌트stable-systemd 기준Cross build 영향
Binutils Pass 1/22.45링커 기본 동작 및 DTAGS/hash 스타일
GCC Pass 1/215.2.0libgcc, libstdc++, PIE/SSP 기본값
Linux API Headers6.16.1glibc가 참조하는 커널 UAPI 인터페이스
Glibc2.42동적 로더 경로, CRT 파일, libc ABI
systemd257.8최종 사용자 공간 init 동작(Ch.8 이후)
운영 팁: 문서 본문 예시 버전과 실제 stable-systemd 버전이 다르면, configure 옵션은 유지하고 버전 문자열/경로만 우선 치환한 뒤 테스트를 재실행하세요.

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. 소스 무결성: 패키지/패치 해시 점검 후 시작
  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
# 이후 책의 해당 장 커맨드 순서대로 재실행
Cross Build 품질 게이트 Phase 1 Cross Toolchain Ch.5 Gate A dummy.log sanity 동적로더/CRT/headers Phase 2 Temp Tools + Pass2 Ch.6 Gate B Chroot 품질 게이트 /tools 비활성 + PATH 검증 LFS Cross Build 품질 게이트 모델 문제가 생기면 다음 단계로 넘어가지 않고 게이트에서 복구
그림 13. Cross build 품질 게이트 — Chapter 5/6/7 전환 시 검증 우선 전략

크로스 빌드 트러블슈팅

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

흔한 에러와 해결 방법

증상원인해결
cannot find -lgcc 크로스 컴파일러의 libgcc를 찾지 못함 $LFS/tools/lib/gcc/$LFS_TGT/14.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 -dNEEDED 라이브러리가 $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 위에 그래픽, 네트워크, 멀티미디어 등을 추가하는 가이드입니다.

BLFS 확장 경로 LFS → BLFS 확장 경로 LFS 기본 시스템 (81 패키지) 보안 & 네트워크 OpenSSH, Wget, cURL GnuTLS, NSS, sudo iptables/nftables, WireGuard Linux-PAM, Polkit, PCSC-Lite 그래픽 & X Window Xorg Server, Mesa (OpenGL) Wayland, libinput, Vulkan GTK+4, Qt6, Cairo, Pango Fontconfig, FreeType, HarfBuzz GNOME / KDE Plasma Xfce / LXQt / i3 서버 & 개발 Apache/Nginx, MariaDB PHP, Node.js, PostgreSQL Git, CMake, LLVM/Clang Rust, Go, Java (OpenJDK) 완전한 데스크톱/서버 시스템 (LFS + BLFS 수백 패키지) 데스크톱 시스템: LFS 81 + BLFS 200~400 패키지 | 서버 시스템: LFS 81 + BLFS 50~100 패키지 예상 빌드 시간: LFS ~50 SBU + BLFS 데스크톱 ~300 SBU | 전체 약 2~5일 (하드웨어 의존)
그림 17. 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 애플리케이션 프레임워크
폰트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주소 공간 배치 랜덤화 (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%) • $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 내장
그림 18. LFS 빌드 흔한 실수 분류 — 환경 변수 실수가 전체의 40%로 가장 빈번

자주 묻는 질문 (FAQ)

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

요약 및 참고 자료

핵심 개념 요약

LFS 학습 로드맵 LFS 학습 로드맵 사전 학습 리눅스 CLI 기초 GCC/Make 기본 사용법 LFS 빌드 소스에서 시스템 빌드 크로스 컴파일 이해 BLFS 확장 데스크톱/서버 구축 패키지 의존성 관리 심화 과정 커널 커스터마이징 패키지 매니저 구축 배포판 제작 자체 배포판 구축 임베디드 시스템 초급 중급 중상급 고급 전문가 관련 학습 자료 (이 사이트) GCC 컴파일러 | Binutils 빌드 시스템 | ELF 커널 컴파일 | 부팅 과정 Systemd | 디바이스 드라이버 파일시스템 | 메모리 관리 네트워킹 | 프로세스 관리
그림 19. LFS 학습 로드맵 — 사전 학습부터 자체 배포판 제작까지의 단계별 경로

공식 문서 및 프로젝트

커뮤니티 및 지원

관련 기술 문서

참고 서적

서적저자설명
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에서 설치

이 주제와 관련된 다른 문서를 더 깊이 이해하고 싶다면 다음을 참고하세요.