커널 개발 환경 설정

Linux 커널 개발을 위한 개발 환경 구축 가이드: 필수 도구 설치, 에디터 설정, QEMU/KVM 가상 환경, 크로스 컴파일(Cross Compilation), GDB/KGDB 디버거 설정까지 완벽 정리.

전제 조건: 처음 방문했다면 메인 페이지(Page)에서 전체 학습 경로를 먼저 확인하세요. 이 문서는 바로 읽어도 되지만, 카테고리 구조를 먼저 파악하면 이후 빌드 시스템(Build System), QEMU, 디버깅(Debugging) 문서를 연결해서 따라가기 쉽습니다.
일상 비유: 이 주제는 작업장 공구 세팅과 비슷합니다. 목공 작업에 톱, 망치, 드릴이 필요하듯이, 커널 개발에는 컴파일러, 디버거, 에디터가 필수입니다. 도구를 제대로 갖추면 작업 효율이 크게 높아집니다.

핵심 요약

  • 필수 도구 — gcc, make, git, flex, bison, libelf-dev 등 빌드에 필수적인 패키지를 먼저 설치합니다.
  • 개발 보조 도구 — ctags, cscope, clangd 등으로 코드 탐색과 자동완성을 강화합니다.
  • 가상 환경 — QEMU/KVM으로 안전하게 커널을 테스트하고 디버깅(Debugging)합니다.
  • 크로스 컴파일 — ARM, ARM64, RISC-V 등 다른 아키텍처용 커널을 빌드합니다.
  • 디버거 설정 — GDB/KGDB로 커널 소스 레벨 디버깅을 수행합니다.

단계별 이해

  1. 도구 설치
    배포판에 맞는 패키지 관리자로 필수 도구를 설치합니다.

    왜? 커널 빌드는 GCC/Clang 컴파일러 외에도 flex·bison(파서 생성), libelf-dev(BPF 지원), bc(설정 스크립트 계산) 등 수십 개의 보조 도구가 얽혀 있습니다. 하나라도 빠지면 make defconfig 단계에서 즉시 오류가 나므로, 첫 단계에서 올바른 패키지 세트를 설치해야 이후 과정이 막히지 않습니다.

  2. 에디터 구성
    선호하는 에디터에 코드 탐색 도구를 연동합니다.

    왜? 커널 소스는 약 3,500만 줄에 달합니다. ctags·cscope·clangd 없이 grep만으로 함수 정의와 호출 관계를 추적하면 수십 분이 걸립니다. compile_commands.json을 생성하면 에디터가 커널 매크로와 조건부 컴파일 분기까지 이해해 정확한 자동완성·점프가 가능해집니다.

  3. 가상 환경 준비
    QEMU/KVM으로 테스트용 가상 머신을 구성합니다.

    왜? 실제 하드웨어에서 커널 버그를 실험하면 시스템이 패닉(Panic)에 빠지거나 파일시스템이 손상될 수 있습니다. QEMU는 빌드한 커널 이미지를 격리된 환경에서 1초 안에 부팅하고, 크래시(Crash)가 발생해도 호스트에 영향을 주지 않습니다. GDB 원격 디버깅 포트도 QEMU 옵션 한 줄로 열립니다.

  4. 첫 빌드 실행
    간단한 설정으로 커널을 빌드하고 부팅 테스트합니다.

    왜? make defconfig는 현재 아키텍처의 합리적 기본값을 적용한 최소 빌드 설정입니다. 4,000개 이상의 옵션을 직접 건드리기 전에 이 설정으로 먼저 전체 빌드~QEMU 부팅 루프가 동작하는지 확인해야, 이후 옵션 추가 시 문제의 원인이 새 설정에 있다고 특정할 수 있습니다.

  5. 디버거 연동
    GDB와 QEMU를 연결하여 커널 디버깅 환경을 완성합니다.

    왜? 커널에서 printk만으로 디버깅하면 심각한 타이밍 의존 버그나 메모리 오염은 발견하기 어렵습니다. CONFIG_DEBUG_INFO로 빌드한 커널과 QEMU의 -s -S 옵션을 함께 사용하면, GDB에서 커널 소스 라인 단위 중단점·변수 조사·스택 트레이스를 실시간(Real-time)으로 수행할 수 있습니다.

환경 설계 원칙

커널 개발 환경은 단순 설치보다 재현성, 격리(Isolation), 검증 가능성이 중요합니다. 처음 한 번만 잘 구성하면 이후 실험 속도와 안정성이 크게 올라갑니다.

원칙 설명 실무 권장
재현성 같은 입력이면 같은 빌드 결과가 나와야 함 툴 버전 고정, 설정 파일(.config) 보관, 빌드 로그 아카이브
격리 호스트 시스템과 테스트 환경 분리 QEMU/KVM 기본, 실제 장비는 후반 검증 단계에서만 사용
검증 가능성 문제 발생 시 원인 추적이 가능해야 함 CONFIG_DEBUG_INFO, FRAME_POINTER, 로그 수집 자동화
점진적 확장 필수 도구부터 시작해 점진적으로 추가 필수(빌드) → 권장(탐색/가상화(Virtualization)) → 선택(분석/자동화)
권장 시작 프로필: 초반에는 단일 아키텍처(x86_64) + QEMU + GDB 조합으로 시작하세요. 크로스 컴파일과 고급 분석 도구는 기본 루프(수정→빌드→부팅→디버깅)가 안정화된 뒤 추가하는 편이 전체 학습 속도가 빠릅니다.

개발 도구 의존성 로드맵

커널 개발 환경은 여러 도구들이 계층적으로 연결된 생태계입니다. 아래 다이어그램은 각 도구의 역할과 의존 관계를 보여주며, 환경 구축 순서를 안내합니다.

커널 개발 도구 의존성 로드맵 Layer 0: 기본 시스템 Linux 배포판 패키지 관리자 Bash/Shell Python3 Perl Layer 1: 핵심 빌드 도구 (필수) GCC gcc-12+ GNU Make make 3.82+ binutils ld, as, ar flex/bison 파서 생성 libelf-dev BTF/BPF libssl-dev 모듈 서명 Git 버전 관리 Layer 2A: 코드 탐색 (권장) ctags 심볼 인덱싱 cscope 참조 추적 clangd LSP 서버 ripgrep Layer 2B: 가상화 (권장) QEMU 에뮬레이터 KVM 하드웨어 가속 virtme-ng 빠른 테스트 busybox Layer 3: 디버깅 & 분석 (선택) GDB 소스 디버깅 crash vmcore 분석 perf 프로파일링 trace-cmd ftrace UI bpftrace 동적 추적 sparse 정적 분석 coccinelle 코드 변환 checkpatch 스타일 검사 pahole Layer 4: 고급 도구 (전문가) 크로스 컴파일 툴체인 ccache / distcc clang / LLVM ktest / kernelci syzkaller (fuzzing) b4 (패치(Patch) 관리) Rust 툴체인
그림: 커널 개발 도구 의존성 로드맵 - 계층별 설치 순서
💡

환경 구축 권장 순서:

  1. 최소 환경 (1~2시간): Layer 0-1 + QEMU → 간단한 커널 빌드/부팅 가능
  2. 기본 개발 (반나절): + Layer 2A/2B → 코드 탐색 및 가상머신 테스트
  3. 완전한 환경 (1일): + Layer 3 → 디버깅 및 분석까지 모든 작업 가능
  4. 전문가 환경 (지속): + Layer 4 → 다중 아키텍처 개발 및 자동화

디스크 공간: 커널 소스 3GB + 빌드 결과 10GB + 가상머신 이미지 5GB = 최소 20GB 여유 필요

커널 빌드 파이프라인(Build Pipeline) 개요

make -j$(nproc) 한 줄 뒤에서는 수만 개의 C 소스 파일이 6단계 변환 과정을 거쳐 최종 vmlinuxbzImage로 합쳐집니다. 이 흐름을 이해하면 "왜 이 도구가 필요한가?"가 자연스럽게 풀립니다.

커널 빌드 파이프라인 6단계 — 소스→vmlinux/bzImage ① 소스 코드 .c / .h / .S git / kbuild ② 전처리 cpp / gcc -E #include·#define 전개 ③ 컴파일 gcc cc1 / clang C → 어셈블리 코드 ④ 어셈블 GNU as / llvm-as 어셈블리 → .o 파일 ⑤ 링크 ld / lld .o 파일들 → vmlinux ⑥ 패키징 objcopy / scripts/ vmlinux → bzImage 전체 흐름을 조율하는 Kbuild 시스템 — GNU Make + Makefile 계층 구조
그림: 커널 빌드 파이프라인 — make 한 줄이 내부적으로 실행하는 6단계 변환
단계담당 도구입력출력패키지
① 전처리 cpp (gcc 내장) .c, .h 매크로(Macro) 전개된 C 텍스트 gcc
② 컴파일 gcc cc1 / clang 전처리 결과 어셈블리(Assembly) 코드 (.s) gcc / clang
③ 어셈블 as (GNU binutils) .s / .S 오브젝트 파일(.o) binutils
④ 링크 ld (GNU binutils) 수천 개의 .o vmlinux (ELF) binutils
⑤ 패키징 objcopy, 커널 스크립트 vmlinux bzImage / Image.gz binutils, bc
⑥ BTF 생성 pahole vmlinux DWARF 정보 BTF 섹션 삽입 (BPF·eBPF 지원) dwarves
Kbuild 시스템이란? 커널 전용 빌드 시스템으로, 루트 Makefile이 각 서브시스템 Makefile을 재귀 호출하여 병렬 컴파일을 조율합니다. obj-y(빌트인), obj-m(모듈), obj-$(CONFIG_XXX)(조건부)로 빌드 대상을 선언하며, Kconfig 설정에 따라 어떤 파일을 컴파일할지 결정합니다. 개발 중에는 make drivers/net/my_driver.o처럼 단일 파일만 재컴파일하는 것도 가능합니다.

필수 개발 도구 설치

Linux 커널 빌드를 위해서는 컴파일러, 빌드 시스템, 버전 관리 시스템, 그리고 다양한 유틸리티가 필요합니다. 배포판별로 패키지 이름이 다를 수 있으므로 각 배포판에 맞는 명령어를 사용하세요.

Ubuntu / Debian 계열

# 필수 빌드 도구
sudo apt update
sudo apt install -y build-essential \
  gcc make git pkg-config \
  flex bison \
  libelf-dev libssl-dev \
  bc libncurses-dev \
  cpio rsync

# 커널 문서 빌드 도구 (선택)
sudo apt install -y python3-sphinx \
  texlive-latex-base texlive-latex-extra

# 추가 유틸리티
sudo apt install -y kmod dwarves \
  sparse ccache
패키지 설명:
  • build-essential: gcc, g++, make 등 기본 빌드 도구 모음
  • flex, bison: 파서 생성기 (커널 빌드 스크립트에서 사용)
  • libelf-dev: BPF, eBPF 프로그램 빌드에 필요
  • libssl-dev: 서명된 커널 모듈 빌드에 필요
  • bc: 커널 빌드 스크립트의 계산기
  • libncurses-dev: menuconfig TUI에 필요
  • pkg-config: libelf, openssl 등 라이브러리 존재 여부를 스크립트로 검증할 때 사용
  • dwarves: pahole 등 DWARF 디버깅 정보 분석 도구
  • sparse: 정적 분석 도구
  • ccache: 컴파일러 캐시(Cache)로 재빌드 속도 향상
비직관적 의존성 — 왜 이 패키지가 필요한가?
패키지빌드 파이프라인 역할없으면?
flex / bison Kconfig 파서와 일부 커널 서브시스템(DTB 컴파일러 등)의 렉서·파서를 소스에서 생성합니다. 커널 scripts/kconfig/ 디렉토리가 이를 사용합니다. make defconfig 또는 menuconfig 단계에서 "No rule to make target" 오류
libelf-dev ELF(Executable and Linkable Format) 파일 파싱 라이브러리. pahole(BTF 생성), BPF 로더(Loader), objtool이 의존합니다. CONFIG_DEBUG_INFO_BTF 또는 BPF 관련 빌드에서 링크 오류
bc 셸에서 부동소수점 없이 정밀 정수 연산이 필요한 커널 빌드 스크립트(예: 아키텍처별 타임슬롯 계산)에 사용됩니다. arch 별 빌드 스크립트 중간에 "bc: command not found" 오류
dwarves (pahole) vmlinux에 포함된 DWARF 타입 정보를 읽어 BTF(BPF Type Format) 섹션을 삽입합니다. BPF 프로그램이 커널 구조체 오프셋(Offset)에 접근하는 데 필수입니다. CONFIG_DEBUG_INFO_BTF=y 빌드 시 "FAILED: load BTF from vmlinux" 오류
libssl-dev 커널 모듈 서명(CONFIG_MODULE_SIG) 및 보안 부트(Secure Boot) 지원에 사용됩니다. scripts/sign-file.c가 OpenSSL API를 호출합니다. 모듈 서명 빌드 시 헤더 누락 컴파일 오류
libncurses-dev make menuconfig의 TUI(Terminal UI)를 렌더링하는 ncurses 라이브러리입니다. make menuconfig 실행 시 "Your display is too small" 또는 링크 오류

설치 직후 검증 명령

패키지 설치가 끝나면 바로 아래 명령으로 도구 상태를 확인하세요. 설치 자체보다 실행 가능한 상태를 검증하는 과정이 중요합니다.

# 필수 도구 버전 확인
gcc --version | head -1
make --version | head -1
git --version
ld --version | head -1
flex --version
bison --version | head -1

# 커널 빌드 관련 라이브러리 존재 확인
pkg-config --modversion libelf
openssl version

# 커널 소스에서 최소 빌드 검증
make mrproper
make defconfig
make -j$(nproc) bzImage
검증 포인트: make defconfig가 실패하면 ncurses, flex, bison, bc 계열 의존성이 누락됐을 가능성이 큽니다. bzImage 빌드가 실패하면 컴파일러/링커(Linker)/헤더 버전 조합을 우선 확인하세요.

버전 관리 정책

커널 개발에서는 "최신 버전"보다 "팀 전체에서 동일한 조합"이 더 중요할 때가 많습니다. 도구 버전을 팀 기준으로 고정하면 재현 불가 버그를 크게 줄일 수 있습니다.

도구 최소 버전 요구사항 (v6.14+ 기준)

아래는 커널 Documentation/process/changes.rst에 명시된 공식 최소 버전과 실무 권장 버전입니다. 최소 버전 미만의 도구로 빌드하면 경고 또는 오류가 발생합니다. 커널 버전마다 최소 버전이 상이할 수 있으므로, 실제 빌드하려는 커널 소스 트리에서 scripts/min-tool-version.sh를 실행하여 정확한 최소 버전을 확인하세요.

도구 최소 버전 (v6.14+) 권장 버전 비고
GCC 8.1 13+ v6.13까지는 5.1, v6.14+는 8.1 이상 필요. 실무에서는 12+ 권장
Clang/LLVM 15.0.0 19+ v6.9~v6.13: 13.0.1, v6.14+: 15.0.0. AutoFDO는 LLVM 19+ 필요
Rust (선택) 1.78.0 최신 stable CONFIG_RUST 활성화 시 필요, 커널 마이너 버전별로 요구 버전이 다를 수 있습니다 (v6.14: 1.83.0 권장)
bindgen (선택) 0.65.1 최신 Rust C 바인딩(Binding) 생성기, 커널 버전별 상이
GNU Make 4.0 4.4+ v6.14+에서는 4.0 이상 필수
binutils 2.30 2.40+ ld, as, ar, objcopy 포함. v6.14+에서는 2.30 이상
flex 2.5.35 2.6+
bison 2.0 3.8+
pahole 1.22 1.25+ BTF 생성 (CONFIG_DEBUG_INFO_BTF), v6.14+에서는 1.22 이상
Perl 5 5.34+ checkpatch.pl, 빌드 스크립트
Python 3.9.x 3.10+ Sphinx 문서, 여러 가지 빌드/테스트 스크립트. v6.14+에서는 3.9 이상
openssl 1.0.0 3.x 모듈 서명 (CONFIG_MODULE_SIG)
버전 확인 방법: scripts/min-tool-version.sh로 현재 커널 소스가 요구하는 도구 최소 버전을 즉시 확인할 수 있습니다. 이 스크립트는 커널 소스 트리마다 해당하는 최소 버전을 반환하므로, 빌드하려는 커널 버전의 소스 디렉토리에서 실행하세요.
# 커널 소스 디렉토리에서 실행 (현재 트리의 최소 버전 반환)
scripts/min-tool-version.sh gcc       # 예: 8.1 (v6.14+)
scripts/min-tool-version.sh llvm      # 예: 15.0.0
scripts/min-tool-version.sh rustc     # 예: 1.78.0
scripts/min-tool-version.sh bindgen   # 예: 0.65.1
scripts/min-tool-version.sh binutils  # 예: 2.30
Rust/bindgen 버전 정책(Rust-for-Linux): Rust-for-Linux는 현재 Debian stable(2025.08 릴리스된 Trixie 기준)에 탑재된 Rust/bindgen 버전을 기준선으로 추적합니다. 이에 따라 향후 커널 버전의 최소 요구값 후보로 rustc 1.85·bindgen 0.71.1 조합이 자주 언급됩니다. 다만 실제 요구값은 커널 트리의 scripts/min-tool-version.sh와 Rust-for-Linux 정책 문서를 우선 확인해야 합니다. 빌드 환경을 미리 맞추려면 rustup으로 최신 stable을 설치하고 rust-src 컴포넌트와 bindgen-cli를 최신 버전으로 유지하는 것을 권장합니다.

Fedora / RHEL / CentOS 계열

# 필수 빌드 도구
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y gcc make git pkgconf-pkg-config \
  flex bison \
  elfutils-libelf-devel openssl-devel \
  bc ncurses-devel \
  cpio rsync

# 추가 유틸리티
sudo dnf install -y kmod dwarves \
  sparse ccache

Arch Linux

# 필수 빌드 도구
sudo pacman -S --needed base-devel pkgconf \
  gcc make git \
  flex bison \
  libelf openssl \
  bc ncurses \
  cpio rsync

# 추가 유틸리티
sudo pacman -S kmod pahole \
  sparse ccache

LLVM/Clang 대체 툴체인

리눅스 커널은 GCC 외에도 LLVM/Clang으로 공식 빌드를 지원합니다. Clang은 더 상세한 경고 메시지, CFI(Control Flow Integrity), 링크 타임 최적화(LTO) 등 GCC에 없는 보안/최적화 기능을 제공합니다.

LLVM/Clang 설치

# Ubuntu/Debian (배포판 기본 LLVM 패키지)
sudo apt install -y clang lld llvm

# Fedora
sudo dnf install -y clang lld llvm

# Arch Linux
sudo pacman -S clang lld llvm
버전 선택 기준: 업스트림 커널 문서는 배포판이 제공하는 최신 stable LLVM 사용을 일반적으로 권장합니다. 배포판 기본 패키지가 너무 오래됐다면 별도 LLVM 저장소나 kernel.org에서 제공하는 사전 빌드 LLVM을 검토하세요.

Clang으로 커널 빌드

# 기본 Clang 빌드
make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm \
     STRIP=llvm-strip OBJCOPY=llvm-objcopy \
     OBJDUMP=llvm-objdump READELF=llvm-readelf \
     HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar \
     defconfig

# 간편한 방법: LLVM=1 (모든 도구를 LLVM으로)
make LLVM=1 defconfig
make LLVM=1 -j$(nproc)

# 접미사 버전 패키지(clang-18 등)를 설치했다면
make LLVM=-${LLVM_VERSION} defconfig
make LLVM=-${LLVM_VERSION} -j$(nproc)

# Clang으로 크로스 컴파일 (단일 바이너리로 모든 아키텍처)
make LLVM=1 ARCH=arm64 defconfig
make LLVM=1 ARCH=arm64 -j$(nproc)

# AutoFDO 빌드 (v6.12+, LLVM 19+ 필요)
# 1단계: 프로파일 수집용 커널 빌드
make LLVM=1 defconfig
./scripts/config --enable AUTOFDO_CLANG
make LLVM=1 -j$(nproc)
# 2단계: perf로 프로파일 수집 후 재빌드
# perf record -b -o perf.data -- workload
# create_llvm_prof --binary=vmlinux --out=afdo.prof
# make LLVM=1 CLANG_AUTOFDO_PROFILE=afdo.prof -j$(nproc)

Clang 전용 기능

기능 설정 옵션 설명
CFI CONFIG_CFI_CLANG 간접 호출 대상 검증, 코드 재사용 공격 방어
LTO (Thin) CONFIG_LTO_CLANG_THIN 링크 타임 최적화 (전체 프로그램 최적화)
Shadow Call Stack CONFIG_SHADOW_CALL_STACK ROP 공격 방어 (ARM64)
KCFI CONFIG_CFI_CLANG 커널 전용 CFI 구현 (v6.1+, 기존 CFI 대체)
Auto-init CONFIG_INIT_STACK_ALL_ZERO 스택 변수 자동 초기화 (정보 유출 방지)
AutoFDO CONFIG_AUTOFDO_CLANG 프로파일 기반 최적화, perf 데이터로 핫 패스 최적화 (v6.12+, LLVM 19+)
Propeller CONFIG_PROPELLER_CLANG 포스트 링크 코드 레이아웃 최적화, AutoFDO와 병용 (v6.12+, LLVM 19+)

GCC vs Clang 비교

항목 GCC Clang/LLVM
역사 커널 공식 기본 컴파일러 4.x부터 공식 지원, Android 커널 기본
에러 메시지 간결 상세하고 컬러풀, 제안 포함
경고 수준 보수적 더 많은 잠재 문제 감지
크로스 컴파일 아키텍처별 별도 툴체인 단일 바이너리로 모든 아키텍처
LTO 지원 (느림) ThinLTO로 빠르고 효율적
보안 기능 기본 CFI, Shadow Call Stack 등 추가
빌드 속도 보통 비슷하거나 약간 빠름
플러그인 GCC 플러그인 지원 미지원 (대안 기능 제공)
실무 권장: 개발 중에는 GCC와 Clang 모두로 빌드하면 더 많은 경고를 잡을 수 있습니다. GCC에서 통과하는 코드가 Clang에서 경고를 발생시키는 경우(또는 그 반대)가 적지 않습니다. CI에서 양쪽 컴파일러 모두 테스트하는 것이 이상적입니다.
# 양쪽 컴파일러로 빌드 테스트
# GCC 빌드
make O=build-gcc defconfig
make O=build-gcc -j$(nproc) 2>&1 | tee gcc-warnings.log

# Clang 빌드
make O=build-clang LLVM=1 defconfig
make O=build-clang LLVM=1 -j$(nproc) 2>&1 | tee clang-warnings.log

# 경고 비교
diff <(grep "warning:" gcc-warnings.log | sort) \
     <(grep "warning:" clang-warnings.log | sort)

Rust 커널 개발 환경

리눅스 커널은 v6.1부터 Rust를 지원하기 시작했으며, Linux 7.0 (2026년 4월 12일)에서 experimental 태그가 제거되어 stable로 전환되었습니다. v6.12~v7.0에 걸쳐 Rust 추상화 계층이 크게 확장되어, 디바이스 드라이버(Device Driver)와 파일시스템(Filesystem) 모듈을 Rust로 작성할 수 있는 기반이 마련되었습니다. Rust는 이제 C와 나란히 공식 kernelsupported 언어로, 새로운 커널 코드 작성에 있어 memory safety를 보장하는 선택지가 되었습니다.

Rust 툴체인 설치

# rustup으로 Rust 설치 (커널이 요구하는 특정 버전)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

# 커널 소스에서 요구하는 Rust 버전 확인
cd /path/to/linux
scripts/min-tool-version.sh rustc    # 예: 1.78.0
scripts/min-tool-version.sh bindgen  # 예: 0.69.5

# 해당 버전 설치 및 필수 컴포넌트 추가
rustup override set $(scripts/min-tool-version.sh rustc)
rustup component add rust-src

# bindgen 설치
cargo install --locked bindgen-cli

# Rust 지원 여부 확인
make LLVM=1 rustavailable
요구사항: Rust 커널 빌드는 LLVM=1(Clang)을 필수로 사용합니다. GCC만으로는 Rust 커널 코드를 빌드할 수 없습니다. make rustavailable이 성공하면 CONFIG_RUST=y를 활성화할 수 있습니다.

Rust 포함 커널 빌드

# Rust 활성화 커널 빌드
make LLVM=1 defconfig
./scripts/config --enable RUST
make LLVM=1 -j$(nproc)

# Rust 샘플 모듈 활성화 (학습용)
./scripts/config --enable SAMPLE_RUST_MINIMAL
./scripts/config --enable SAMPLE_RUST_PRINT
make LLVM=1 -j$(nproc)

Rust 커널 프로그래밍의 상세 가이드 — 추상화 계층, 드라이버 작성, 안전성 모델, KUnit 연동은 별도 페이지로 분리되었습니다.

Rust 커널 프로그래밍 가이드 → | Rust 언어 기초~고급 →

코드 탐색 도구

ctags, cscope, clangd 등 코드 탐색 도구의 설치, 에디터 통합, 인덱스 관리 전략은 별도 페이지로 분리되었습니다.

소스 코드 읽기 가이드 →

에디터 설정

Vim, VS Code, Emacs, Neovim의 커널 개발 최적화 설정은 별도 페이지로 분리되었습니다.

에디터 설정 가이드 →

QEMU/KVM 가상 환경 설정

QEMU 설치, rootfs 생성, 커널 부팅, 빠른 테스트 루프, 부팅 실패 대응 등 QEMU/KVM 가상 환경의 상세 가이드는 별도 페이지로 분리되었습니다.

QEMU 가상 환경 가이드 →

virtme-ng: 빠른 커널 테스트

virtme-ng는 별도 rootfs 없이 호스트 파일시스템(Filesystem)을 공유하여 빌드한 커널을 즉시 부팅하는 도구입니다. 설치, 사용법, QEMU와의 비교는 QEMU 가이드에서 확인할 수 있습니다.

QEMU 가이드: virtme-ng 섹션 →

initramfs 직접 생성

BusyBox 기반 initramfs 생성, 커널 내장 initramfs, 고급 구성 등 상세 가이드는 QEMU 페이지에서 확인할 수 있습니다.

QEMU 가이드: initramfs 섹션 →

BusyBox 멀티콜 바이너리 아키텍처, 애플릿 시스템 등 심층 내용은 BusyBox 종합 가이드를 참고하세요.

크로스 컴파일 환경

ARM, ARM64, RISC-V 크로스 컴파일 환경 구축은 별도 페이지로 분리되었습니다.

크로스 컴파일 환경 가이드 →

GDB/KGDB 디버거 설정

GDB/KGDB를 이용한 커널 소스 레벨 디버깅 — QEMU-GDB 연동 워크플로, GDB 명령어, KGDB 실제 하드웨어 디버깅 등 상세 가이드는 별도 페이지로 분리되었습니다.

디버깅 가이드 → | QEMU 가이드: 커널 디버깅 섹션 →

디버그 커널 설정 옵션 총정리

커널 디버그 CONFIG 옵션 카테고리별 정리, 목적별 프로필, Sanitizer 조합 가이드는 별도 페이지로 분리되었습니다.

디버그 설정 옵션 가이드 →

빌드 속도 최적화

ccache (컴파일러 캐시)

ccache는 컴파일 결과를 캐싱하여 재빌드 속도를 크게 향상시킵니다.

# ccache 설치 (이미 위에서 설치됨)
sudo apt install ccache

# ccache 캐시 크기 설정 (기본 5GB, 10GB 권장)
ccache -M 10G

# ccache 통계 확인
ccache -s

# 커널 빌드 시 ccache 사용
make CC="ccache gcc" -j$(nproc)

# 또는 PATH에 ccache 심볼릭 링크 추가
export PATH="/usr/lib/ccache:$PATH"
make -j$(nproc)

distcc (분산 컴파일)

여러 머신을 사용하여 병렬로 컴파일하면 빌드 시간을 대폭 단축할 수 있습니다.

# 서버 머신에서 distccd 실행
sudo apt install distcc
distccd --daemon --allow 192.168.1.0/24

# 클라이언트 머신에서 빌드
export DISTCC_HOSTS="localhost 192.168.1.100 192.168.1.101"
make CC="distcc gcc" -j16
주의: 분산 빌드는 네트워크 지연(Latency)과 전처리 비용에 따라 오히려 느려질 수 있습니다. 먼저 ccache만으로 이득을 확인한 뒤, 대형 소스 트리에서만 distcc를 추가하는 순서가 안전합니다.

빌드 환경 성능 튜닝

커널 빌드 성능은 디스크 I/O, 병렬 작업 수, 캐시 효율에 크게 좌우됩니다. 아래 기법으로 빌드 시간을 50% 이상 단축할 수 있습니다.

tmpfs 빌드 (RAM 디스크)

# 별도 빌드 디렉토리를 tmpfs에 마운트
sudo mkdir -p /mnt/kbuild
sudo mount -t tmpfs -o size=15G tmpfs /mnt/kbuild

# 소스와 빌드 디렉토리 분리 (O= 옵션)
cd /home/user/linux
make O=/mnt/kbuild defconfig
make O=/mnt/kbuild -j$(nproc)

# 영구 설정: /etc/fstab에 추가
# tmpfs /mnt/kbuild tmpfs size=15G,mode=1777 0 0
주의: tmpfs는 RAM을 사용합니다. 최소 32GB RAM에서 15GB 할당을 권장합니다. 시스템 메모리가 부족하면 OOM Killer가 작동할 수 있습니다.

병렬 작업 수 최적화

# 기본: CPU 코어 수
make -j$(nproc)

# 코어 수 + 2 (I/O 대기 보상)
make -j$(( $(nproc) + 2 ))

# 메모리 제한 고려: 코어당 2GB 필요 (LTO 시)
# 16GB RAM, 8코어 → -j8이 안전
# 8GB RAM, 8코어 → -j4 권장

# 백그라운드 빌드 (낮은 우선순위)
nice -n 19 ionice -c3 make -j$(nproc)

증분 빌드 최적화

기법 명령 효과
단일 파일 빌드 make drivers/net/my_driver.o 컴파일 오류만 빠르게 확인
단일 디렉토리 빌드 make drivers/net/ 서브시스템 전체 빌드
모듈만 빌드 make modules vmlinux 재링크 건너뜀
ccache + 분리 빌드 make CC="ccache gcc" O=build/ 캐시 히트로 재빌드 10초 이내
전처리만 확인 make drivers/net/my_driver.i 매크로(Macro) 전개 결과 확인
어셈블리(Assembly) 확인 make drivers/net/my_driver.s 컴파일러 출력 코드 확인
커널 빌드 성능 최적화 비교 빌드 시간 비교 (x86_64 defconfig, 8코어 기준) 기본 HDD -j1 ~45분 SSD -j8 ~8분 SSD + ccache -j8 (재빌드) ~1분 tmpfs+ccache -j8 (재빌드) ~30초 증분 빌드 단일 파일 수정 ~10초 virtme-ng 빌드+부팅 ~15초 ※ 실제 시간은 하드웨어, 커널 설정, 변경 범위에 따라 크게 달라질 수 있음 핵심: ccache + SSD + 증분 빌드 조합이 가장 실용적
그림: 커널 빌드 성능 최적화 비교 - 환경별 빌드 시간 차이

정적 분석 도구

Sparse, Coccinelle, checkpatch.pl 등 커널 정적 분석 도구의 설치와 상세 사용법은 별도 페이지로 분리되었습니다.

개발 도구 가이드: 정적 분석 섹션 → | 코딩 스타일(Coding Style) 가이드 →

커널 셀프테스트 (kselftest)

커널 셀프테스트는 커널 기능의 회귀를 자동으로 검출하는 테스트 프레임워크입니다. tools/testing/selftests/에 서브시스템별 테스트가 있으며, 패치(Patch) 제출 전 관련 테스트를 실행하는 것이 좋습니다.

셀프테스트 실행

# 전체 셀프테스트 빌드 & 실행
make -C tools/testing/selftests run_tests

# 특정 서브시스템 테스트만 실행
make -C tools/testing/selftests TARGETS="net mm" run_tests

# 개별 테스트 빌드
make -C tools/testing/selftests/net

# 크로스 컴파일 셀프테스트
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
  -C tools/testing/selftests TARGETS="bpf"

# 설치 (QEMU rootfs에 복사용)
make -C tools/testing/selftests TARGETS="net" \
  INSTALL_PATH=/path/to/rootfs/kselftest install

주요 테스트 타겟

타겟 테스트 영역 선행 조건
bpf BPF/eBPF 프로그램 CONFIG_BPF_SYSCALL, clang/llvm
net 네트워킹 스택 CONFIG_NET
mm 메모리 관리(Memory Management) CONFIG_USERFAULTFD
cgroup 컨트롤 그룹 CONFIG_CGROUPS
futex Futex 동기화 CONFIG_FUTEX
seccomp Seccomp 필터 CONFIG_SECCOMP
kvm KVM 가상화 CONFIG_KVM
filesystems 파일시스템 공통 다양한 FS CONFIG
rust Rust 커널 모듈 CONFIG_RUST, LLVM 필수
sched_ext 확장 스케줄러(Extensible Scheduler) CONFIG_SCHED_CLASS_EXT (v6.12+)
landlock Landlock 샌드박스(Sandbox) CONFIG_SECURITY_LANDLOCK

테스트 작성 기본 패턴

// tools/testing/selftests/my_subsystem/my_test.c
#include "../kselftest_harness.h"

/* 기본 테스트 */
TEST(my_basic_test)
{
    int result = do_something();

    /* 성공 조건 확인 */
    ASSERT_EQ(result, 0);
    ASSERT_NE(result, -1);
    ASSERT_GT(result, -1);
    EXPECT_TRUE(result >= 0);
}

/* 파라미터화된 테스트 */
FIXTURE(my_fixture)
{
    int fd;
};

FIXTURE_SETUP(my_fixture)
{
    self->fd = open("/dev/mydev", O_RDWR);
    ASSERT_GE(self->fd, 0);
}

FIXTURE_TEARDOWN(my_fixture)
{
    close(self->fd);
}

TEST_F(my_fixture, read_test)
{
    char buf[64];
    ssize_t n = read(self->fd, buf, sizeof(buf));
    ASSERT_GT(n, 0);
}

TEST_HARNESS_MAIN
# tools/testing/selftests/my_subsystem/Makefile
TEST_GEN_PROGS := my_test
include ../lib.mk
kselftest 활용 팁:
  • KSFT_SKIP 반환으로 선행 조건 미충족 시 테스트 건너뛰기
  • make -C tools/testing/selftests TARGETS="net" summary=1로 결과 요약
  • QEMU에서 실행 시 INSTALL_PATH로 rootfs에 테스트 복사 후 실행
  • CI 파이프라인(Pipeline)에 셀프테스트 포함하여 자동 회귀 검사

KUnit 단위 테스트 프레임워크

KUnit은 커널 내장 단위 테스트 프레임워크(v5.5+)로, kselftest가 유저 공간(User Space)에서 커널을 검증하는 반면 KUnit은 커널 공간(Kernel Space) 안에서 직접 실행됩니다. v6.12 이후 Rust 커널 모듈의 KUnit 연동도 지원됩니다.

KUnit 빠른 실행

# 모든 KUnit 테스트 실행 (UML 기반, QEMU 불필요)
./tools/testing/kunit/kunit.py run

# 특정 테스트 스위트만 실행
./tools/testing/kunit/kunit.py run "list_test"

# 특정 아키텍처에서 실행
./tools/testing/kunit/kunit.py run --arch=arm64 --cross_compile=aarch64-linux-gnu-

# QEMU에서 기존 커널로 실행 (모듈로 빌드)
./scripts/config --module KUNIT
./scripts/config --module KUNIT_EXAMPLE_TEST
make -j$(nproc) modules
# QEMU 부팅 후:
modprobe kunit_example_test

KUnit 테스트 작성법, Fixture, 파라미터화 테스트, Rust KUnit 연동, kselftest와의 차이점 비교는 별도 페이지에서 확인할 수 있습니다.

개발 도구 가이드: KUnit 섹션 → | Rust 커널: KUnit 테스트 →

일반적인 개발 워크플로

커널 개발의 핵심은 수정 → 빌드 → 부팅 → 디버깅 반복 루프를 최대한 빠르게 돌리는 것입니다. 아래 다이어그램은 이 루프 전체를 보여주며, 이후 단계별 목록이 각 단계의 "왜?"를 설명합니다.

커널 개발 피드백 루프 — 수정→빌드→부팅→디버깅 ① 코드 수정 vim / VS Code / Emacs drivers/ mm/ net/ fs/ ... make -j$(nproc) ② 빌드 gcc / clang → bzImage ccache로 5~30초 QEMU / virtme-ng ③ 부팅·테스트 QEMU -kernel bzImage kselftest / KUnit 버그 발생 시 ④ 디버깅 GDB / KGDB / KASAN printk / ftrace 반복 (수정 사항 확인 후 다시 ①로) 테스트 통과 → 패치 제출
그림: 커널 개발 피드백 루프 — ccache + virtme-ng 조합으로 총 사이클을 1분 이내로 단축 가능
  1. 소스 다운로드
    git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    cd linux

    왜? 메인라인 Linus 트리를 기준으로 작업해야 패치 제출 시 충돌이 최소화됩니다. 특정 서브시스템 패치라면 해당 메인테이너 트리를 대신 클론하는 것이 좋습니다.

  2. 브랜치 생성
    git checkout -b my-feature

    왜? master에서 직접 수정하면 업스트림 풀(pull) 시 충돌이 발생합니다. 기능별 브랜치를 사용하면 여러 패치를 동시에 개발하고 독립적으로 git format-patch를 생성할 수 있습니다.

  3. 설정 및 빌드
    make defconfig
    ./scripts/config --enable DEBUG_INFO
    make -j$(nproc)

    왜? defconfig는 현재 아키텍처의 검증된 기본값으로, 옵션을 하나씩 고르는 수고 없이 바로 빌드·부팅 가능한 커널을 생성합니다. DEBUG_INFO를 추가하면 GDB에서 소스 라인 단위 디버깅이 활성화됩니다.

  4. 코드 탐색 인덱스 생성
    make tags cscope
    ./scripts/clang-tools/gen_compile_commands.py

    왜? compile_commands.json은 각 소스 파일이 어떤 플래그로 컴파일됐는지 기록합니다. clangd·ccls·clang-tidy가 이 파일을 읽어 커널의 복잡한 매크로와 조건부 컴파일을 올바르게 해석합니다.

  5. 코드 수정 및 테스트
    # 에디터로 코드 수정
    vim drivers/my_driver.c
    
    # 재빌드
    make -j$(nproc)
    
    # QEMU 테스트
    qemu-system-x86_64 -kernel arch/x86/boot/bzImage ...

    왜? 증분 빌드(변경된 파일만 재컴파일)와 ccache 조합이면 단일 파일 수정 후 재빌드가 10초 내외입니다. QEMU 부팅까지 합쳐 1분 안에 루프를 완성할 수 있습니다.

  6. 코딩 스타일 검사
    ./scripts/checkpatch.pl --file drivers/my_driver.c

    왜? 커널 메인테이너는 스타일 오류가 있는 패치를 즉시 반려합니다. 제출 전 반드시 checkpatch.pl이 오류·경고 0건인지 확인해야 합니다.

  7. 정적 분석
    make C=2 drivers/my_driver.o

    왜? C=2는 sparse로 해당 파일의 정적 분석을 수행합니다. __user 포인터 오용, 락(Lock) 불균형, 잘못된 어노테이션 등 런타임에 드러나기 어려운 버그를 빌드 시점에 검출합니다.

  8. 패치 생성
    git add drivers/my_driver.c
    git commit -s
    git format-patch -1

    왜? -s 옵션은 Signed-off-by: 이름 <이메일> 태그를 자동 추가합니다. 커널 기여 프로세스는 모든 커밋에 이 태그를 요구하며, format-patch로 메일 발송 형식의 패치 파일을 생성합니다.

Git 커널 패치 워크플로

리눅스 커널 이메일 기반 패치 워크플로 — git format-patch, git send-email, get_maintainer.pl, b4 도구의 상세 사용법은 별도 페이지로 분리되었습니다.

커널 패치 제출 가이드 →

git bisect (회귀 추적)

특정 커밋에서 버그가 도입된 시점을 이진 탐색으로 찾습니다. 수천 개의 커밋 중에서도 log₂(N) 번의 테스트로 원인 커밋을 특정할 수 있습니다.

# bisect 시작
git bisect start

# 현재(버그 있음) = bad, 정상 동작 커밋 = good
git bisect bad HEAD
git bisect good v6.6

# Git이 중간 커밋을 체크아웃 → 테스트 → good/bad 반복
# 빌드 & 테스트
make -j$(nproc) && qemu-system-x86_64 ...
git bisect good   # 또는 git bisect bad

# 자동 bisect (스크립트로 자동화)
git bisect start HEAD v6.6
git bisect run ./test-script.sh

# bisect 종료 & 정리
git bisect reset
Git 커널 패치 워크플로 1. 코드 수정 git checkout -b fix vim drivers/... make -j$(nproc) 테스트 통과 확인 2. 커밋 작성 git add ... git commit -s Signed-off-by: 필수 50자 제목 + 72자 본문 3. 스타일 검사 checkpatch.pl sparse (C=1) coccicheck 경고 0개 목표 4. 패치 생성 format-patch -1 get_maintainer.pl 수신자 결정 커버 레터 작성 5. 전송 git send-email 또는 b4 send 메일링 리스트 메인테이너 CC 리뷰 사이클 메인테이너 리뷰 Reviewed-by: / Acked-by: 수정 요청 (NAK) 수정 & 재전송 (v2+) format-patch -v2 변경 로그 기록 승인 & 머지 메인테이너 트리에 적용 → linux-next → mainline 릴리스 머지 윈도우 (2주) → rc1 → ... → 릴리스 커널 커밋 메시지 형식 subsystem: Brief summary under 50 chars Detailed explanation... (72 chars/line) | Signed-off-by: Name <email> | Fixes: SHA1 ("original commit")
그림: Git 커널 패치 워크플로 - 코드 수정부터 업스트림 머지까지
커밋 메시지 규칙:
  • 제목: subsystem: 변경 요약 (50자 이내, 마침표 없음)
  • 본문: 왜 변경이 필요한지 설명 (72자/줄)
  • Signed-off-by: DCO(Developer Certificate of Origin) 동의 필수 (git commit -s)
  • Fixes: 버그 수정 시 원인 커밋 SHA 참조
  • Cc: stable 백포트 요청 시 Cc: stable@vger.kernel.org

트러블슈팅 플레이북

아래 순서대로 점검하면 환경 문제를 빠르게 축소할 수 있습니다. 핵심은 문제 범위를 한 단계씩 좁히는 것입니다.

  1. 도구 문제 분리: gcc --version, make --version, ld --version
  2. 설정 문제 분리: make mrproper && make defconfig로 최소 상태 확인
  3. 소스 문제 분리: 같은 커밋을 깨끗한 트리에서 다시 빌드
  4. 런타임 문제 분리: QEMU에서 재현되는지 먼저 확인
  5. 디버깅 단계 진입: GDB 브레이크포인트와 부팅 로그를 함께 확보
오류 메시지 예시 우선 점검 대응
No rule to make target ... 빌드 트리 오염 여부 make mrproper 후 defconfig부터 재시작(Reboot)
fatal error: openssl/... not found 개발 헤더 누락 libssl-dev 또는 openssl-devel 설치
pahole not found dwarves 패키지 설치 여부 dwarves/pahole 설치 후 재빌드
undefined reference ... 툴체인/설정 불일치 ARCH/CROSS_COMPILE/CONFIG 조합 재확인
QEMU 패닉 후 즉시 종료 로그 확보 실패 -nographic + panic=-1 + 로그 파일 저장
로그 수집 최소 세트: 빌드 로그(build.log), QEMU 부팅 로그(qemu-boot.log), 커널 설정(.config), 커밋 해시(Hash)를 항상 함께 보관하세요. 이 네 가지가 있으면 대부분의 환경 문제를 재현하고 분석할 수 있습니다.

고급 트러블슈팅

오류 메시지 / 증상 원인 해결
BTF: .tmp_vmlinux.btf: pahole ... not found CONFIG_DEBUG_INFO_BTF 활성화 + pahole 미설치 sudo apt install dwarves 또는 CONFIG_DEBUG_INFO_BTF=n
zstd: command not found 모듈 압축에 zstd 필요 sudo apt install zstd
GDB Remote 'g' packet reply is too long GDB 아키텍처 불일치 set arch i386:x86-64 또는 gdb-multiarch 사용 (상세)
clangd compile_commands.json not found 컴파일 DB 미생성 ./scripts/clang-tools/gen_compile_commands.py 실행
ccache cache miss 비율 높음 설정 변경, 캐시 크기 부족 ccache -M 20G, KBUILD_BUILD_TIMESTAMP 고정
QEMU Could not access KVM kernel module KVM 모듈 미로드 또는 권한 부족 sudo modprobe kvm_intel, sudo usermod -aG kvm $USER
KASAN BUG: KASAN: slab-out-of-bounds 버퍼(Buffer) 오버플로(Buffer Overflow) 감지 보고된 스택 트레이스에서 접근 위치 확인 후 경계 검사 추가
LOCKDEP possible circular locking 데드락 위험 감지 잠금(Lock) 획득 순서 재검토, 보고된 체인 분석
Kernel panic - not syncing: Attempted to kill init! PID 1(init) 프로세스(Process) 종료 initramfs의 init 스크립트가 exec /bin/sh로 끝나는지 확인
No working init found init 실행 파일 없음 rdinit=/init 파라미터 확인, init에 실행 권한(chmod +x) 확인

환경 진단 스크립트

#!/bin/bash
# kernel-env-check.sh - 커널 개발 환경 진단

echo "=== 커널 개발 환경 진단 ==="
echo

# 필수 도구
echo "[필수 도구]"
for cmd in gcc make git flex bison bc; do
  if command -v $cmd >/dev/null 2>&1; then
    echo "  ✓ $cmd: $($cmd --version 2>&1 | head -1)"
  else
    echo "  ✗ $cmd: 미설치"
  fi
done

# 라이브러리
echo
echo "[필수 라이브러리]"
for lib in libelf openssl; do
  if pkg-config --exists $lib 2>/dev/null; then
    echo "  ✓ $lib: $(pkg-config --modversion $lib)"
  else
    echo "  ✗ $lib: 미설치 또는 dev 패키지 필요"
  fi
done

# 선택 도구
echo
echo "[선택 도구]"
for cmd in clangd ctags cscope qemu-system-x86_64 gdb ccache sparse; do
  if command -v $cmd >/dev/null 2>&1; then
    echo "  ✓ $cmd"
  else
    echo "  - $cmd: 미설치 (선택)"
  fi
done

# KVM
echo
echo "[KVM 지원]"
if [ -e /dev/kvm ]; then
  echo "  ✓ /dev/kvm 존재"
  if [ -r /dev/kvm ] && [ -w /dev/kvm ]; then
    echo "  ✓ 현재 사용자 접근 가능"
  else
    echo "  ✗ 권한 부족: sudo usermod -aG kvm \$USER"
  fi
else
  echo "  ✗ /dev/kvm 없음: BIOS에서 가상화 활성화 필요"
fi

# 디스크/메모리
echo
echo "[시스템 리소스]"
echo "  RAM: $(free -h | awk '/Mem:/{print $2}')"
echo "  디스크 여유: $(df -h . | awk 'NR==2{print $4}')"
echo "  CPU 코어: $(nproc)"

추가 팁

디스크 공간: 커널 소스는 약 3GB, 빌드 산출물은 10GB 이상 차지합니다. SSD에 충분한 공간을 확보하세요.
RAM: 최소 8GB, 권장 16GB 이상. 병렬 빌드(-j 옵션)는 메모리를 많이 소비합니다. OOM 발생 시 병렬도를 낮추세요.
커널 버전 관리: 여러 커널 버전을 동시에 개발하는 경우, git worktree를 사용하면 편리합니다.
# 현재 mainline 트리에서 별도 작업 디렉토리 추가
git worktree add ../linux-mainline master

# linux-next 트리 추가
git remote add linux-next https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
git fetch linux-next master
git worktree add ../linux-next linux-next/master
안정 커널(stable)은 별도 stable remote에서 원하는 linux-6.x.y 유지보수 브랜치를 명시적으로 fetch한 뒤 worktree를 추가하세요.
빠른 부팅 테스트: initramfs를 만들기 전에도 early boot 로그와 패닉 지점까지는 빠르게 확인할 수 있습니다. 실제 initramfs를 붙이는 절차는 QEMU 가이드의 initramfs 섹션을 참고하세요.
make defconfig
make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
  -append "console=ttyS0 panic=-1" \
  -nographic

Docker/Podman 컨테이너(Container) 개발 환경

컨테이너 기반 개발 환경은 호스트 시스템을 오염시키지 않으면서 재현 가능한 빌드 환경을 제공합니다. 팀 전체가 동일한 툴체인 버전을 사용하도록 강제할 수 있어, "내 머신에서는 빌드되는데" 문제를 완전히 차단합니다.

컨테이너 개발의 장점

항목 호스트 직접 설치 컨테이너 환경
재현성 호스트 업데이트에 따라 깨질 수 있음 Dockerfile 고정으로 완전 재현
다중 툴체인 버전 충돌 위험 이미지별 독립 환경
정리 패키지 잔여물 누적 컨테이너 삭제로 깔끔 정리
CI 연동 CI와 로컬 환경 불일치 동일 이미지로 CI/로컬 통일
크로스 컴파일 복잡한 멀티 아키텍처 설정 아키텍처별 전용 이미지

커널 빌드용 Dockerfile

# Dockerfile.kernel-dev
FROM ubuntu:24.04

LABEL maintainer="kernel-dev"
LABEL description="Linux kernel development environment"

# 비대화형 설치
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Seoul

# 필수 빌드 도구
RUN apt-get update && apt-get install -y \
    build-essential gcc g++ make \
    git flex bison pkg-config \
    libelf-dev libssl-dev \
    bc libncurses-dev \
    cpio rsync kmod \
    dwarves sparse ccache \
    \
    # 코드 탐색
    universal-ctags cscope \
    clangd clang lld llvm \
    \
    # 가상화 & 디버깅
    qemu-system-x86 qemu-system-arm \
    gdb gdb-multiarch \
    \
    # 크로스 컴파일
    gcc-aarch64-linux-gnu \
    gcc-arm-linux-gnueabihf \
    gcc-riscv64-linux-gnu \
    \
    # 유틸리티
    vim tmux ripgrep \
    python3 python3-pip \
    curl wget sudo \
    coccinelle \
    \
    && rm -rf /var/lib/apt/lists/*

# Rust 툴체인 (선택, CONFIG_RUST 사용 시)
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
    | sh -s -- -y --default-toolchain none \
    && . "$HOME/.cargo/env" \
    && cargo install --locked bindgen-cli
ENV PATH="/home/${USER}/.cargo/bin:${PATH}"

# ccache 설정
RUN ccache -M 20G
ENV PATH="/usr/lib/ccache:${PATH}"

# 비루트 사용자 생성
ARG USER=kdev
ARG UID=1000
RUN useradd -m -u ${UID} -s /bin/bash ${USER} \
    && echo "${USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

USER ${USER}
WORKDIR /home/${USER}/linux

CMD ["/bin/bash"]

컨테이너 빌드 및 실행

# 이미지 빌드
docker build -t kernel-dev -f Dockerfile.kernel-dev .

# 커널 소스를 마운트하여 실행
docker run -it --rm \
  -v $(pwd)/linux:/home/kdev/linux \
  -v kernel-ccache:/home/kdev/.cache/ccache \
  --device /dev/kvm \
  --name kernel-build \
  kernel-dev

# Podman 사용 시 (rootless)
podman run -it --rm \
  -v $(pwd)/linux:/home/kdev/linux:Z \
  -v kernel-ccache:/home/kdev/.cache/ccache:Z \
  --device /dev/kvm \
  --userns=keep-id \
  kernel-dev

# 컨테이너 안에서 빌드
make defconfig
make -j$(nproc)

# 컨테이너 안에서 QEMU 테스트
qemu-system-x86_64 \
  -kernel arch/x86/boot/bzImage \
  -append "console=ttyS0" \
  -nographic -enable-kvm -m 2G
볼륨 마운트(Mount) 전략:
  • 소스 코드: 호스트의 커널 소스를 바인드 마운트(Bind Mount) → 에디터는 호스트에서, 빌드는 컨테이너에서
  • ccache 캐시: named volume으로 컨테이너 재생성에도 캐시 유지
  • /dev/kvm: KVM 가속을 위해 디바이스 전달
  • 빌드 산출물: 소스 바인드 마운트에 포함되므로 호스트에서도 접근 가능

아키텍처별 컨테이너 전략

# ARM64 크로스 빌드 전용 컨테이너
docker run -it --rm \
  -v $(pwd)/linux:/home/kdev/linux \
  -e ARCH=arm64 \
  -e CROSS_COMPILE=aarch64-linux-gnu- \
  kernel-dev bash -c "make defconfig && make -j\$(nproc)"

# docker-compose.yml로 다중 아키텍처 동시 빌드
# docker compose up --parallel
# docker-compose.yml
services:
  x86-build:
    image: kernel-dev
    volumes:
      - ./linux:/home/kdev/linux
      - ccache-x86:/home/kdev/.cache/ccache
    command: bash -c "make x86_64_defconfig && make -j$(nproc)"

  arm64-build:
    image: kernel-dev
    volumes:
      - ./linux:/home/kdev/linux
      - ccache-arm64:/home/kdev/.cache/ccache
    environment:
      - ARCH=arm64
      - CROSS_COMPILE=aarch64-linux-gnu-
    command: bash -c "make defconfig && make -j$(nproc)"

  riscv-build:
    image: kernel-dev
    volumes:
      - ./linux:/home/kdev/linux
      - ccache-riscv:/home/kdev/.cache/ccache
    environment:
      - ARCH=riscv
      - CROSS_COMPILE=riscv64-linux-gnu-
    command: bash -c "make defconfig && make -j$(nproc)"

volumes:
  ccache-x86:
  ccache-arm64:
  ccache-riscv:
Docker 기반 커널 개발 환경 아키텍처 호스트 시스템 에디터 (호스트) VS Code / Vim clangd / ctags 코드 편집 커널 소스 /home/user/linux/ 바인드 마운트 ↕ 공유 /dev/kvm 하드웨어 가속 디바이스 전달 ccache 볼륨 named volume 영구 캐시 Git 버전 관리 호스트 실행 Docker / Podman 컨테이너 x86_64 빌드 컨테이너 GCC 14 Make / binutils GDB QEMU x86 make defconfig && make -j$(nproc) → bzImage + vmlinux QEMU 부팅 테스트 + GDB 디버깅 ARM64 크로스 빌드 컨테이너 aarch64-gnu-gcc gdb-multiarch QEMU aarch64 DTB 도구 ARCH=arm64 CROSS_COMPILE=aarch64-... → Image (ARM64) QEMU -M virt -cpu cortex-a57 RISC-V 크로스 빌드 컨테이너 riscv64-gnu-gcc gdb-multiarch QEMU riscv64 OpenSBI ARCH=riscv CROSS_COMPILE=riscv64-... → Image (RISC-V) QEMU -M virt (RISC-V) 네이티브 빌드 크로스 빌드 크로스 빌드
그림: Docker 기반 커널 개발 환경 아키텍처 - 호스트에서 편집, 컨테이너에서 빌드/테스트
주의사항:
  • UID 매핑(Mapping): 컨테이너 내부 UID와 호스트 UID가 다르면 소스 파일 권한 문제 발생 → --build-arg UID=$(id -u) 사용
  • 빌드 산출물 소유권: 컨테이너에서 생성한 파일의 소유자가 호스트와 다를 수 있음 → Podman의 --userns=keep-id 권장
  • SELinux: Fedora/RHEL에서는 바인드 마운트에 :Z 접미사 필요

원격 개발 환경

SSH 최적화, tmux, GNU Screen, VS Code Remote Development 설정은 별도 페이지로 분리되었습니다.

원격 개발 환경 가이드 →

커널 설정 전략

커널 설정(.config)은 4000개 이상의 옵션으로 구성됩니다. 목적에 맞는 설정 전략을 세우면 빌드 시간 단축과 디버깅 효율 향상을 동시에 달성할 수 있습니다. 설정 도구(menuconfig, nconfig, xconfig 등)의 상세 비교는 커널 빌드 시스템 페이지를 참고하세요.

Kconfig 시스템 — .config가 만들어지는 원리

커널 옵션이 4,000개 이상인 이유는 단순합니다. 커널은 수천 가지 하드웨어와 시나리오를 지원하며, 각 드라이버·서브시스템·보안 기능마다 "필요한 사람만 켜는" 스위치가 있기 때문입니다. 이 스위치 체계를 Kconfig라 부르며, Kconfig 파일 → menuconfig UI → .config 파일 → 빌드 순서로 동작합니다.

Kconfig 동작 흐름 — Kconfig 파일→menuconfig→.config→빌드 Kconfig 파일들 arch/x86/Kconfig drivers/net/Kconfig 옵션·의존성·메뉴 구조 정의 파싱 설정 도구 make menuconfig (TUI) make defconfig (자동) 사용자 선택 or 기본값 적용 저장 .config 파일 CONFIG_NET=y CONFIG_USB=m # CONFIG_SCSI is not set include Kbuild / make autoconf.h 자동 생성 obj-y / obj-m 결정 → vmlinux / 모듈.ko =y (빌트인) vmlinux에 직접 포함 — 별도 insmod 불필요, 부팅 시 항상 존재 =m (모듈) .ko 파일 생성 — modprobe/insmod로 동적 로드
그림: Kconfig 동작 흐름 — Kconfig 파일이 menuconfig를 거쳐 .config로, 그리고 최종 빌드 결과물로 이어지는 과정
.config 값의미결과언제 선택?
=y 빌트인(Built-in) vmlinux에 정적 포함, 부팅 시 자동 활성화 필수 드라이버·보안 기능, 모듈 로딩 불가 환경
=m 모듈(Module) .ko 파일 생성, 런타임(Runtime) 동적 로드 선택적 드라이버·실험 기능, 빌드 시간 절약
is not set 비활성화 컴파일 안 함, 코드 크기·빌드 시간 절약 불필요한 드라이버·사용하지 않는 기능
Kconfig 의존성 해결: 옵션 A가 depends on B로 선언된 경우, B가 활성화되지 않으면 A는 menuconfig에서 회색 처리됩니다. select B는 반대로 A를 켜면 B도 자동 활성화합니다. make oldconfig는 기존 .config에 새 커널 버전의 추가 옵션을 대화형으로 적용하며, make olddefconfig는 모두 기본값으로 자동 적용합니다.

목적별 설정 전략

커널 설정 전략 플로차트 목적이 무엇인가? 빠른 학습/실험 make tinyconfig → 최소 옵션 (500개 미만) → 빌드 1~2분 → 부팅 불가, 학습 전용 make allnoconfig → 모든 옵션 비활성화 기반 개발/디버깅 make defconfig → 아키텍처 기본 설정 → 빌드 5~15분 → QEMU 부팅 가능 + CONFIG_DEBUG_INFO + CONFIG_GDB_SCRIPTS 배포/하드웨어 대응 make localmodconfig → 현재 로드된 모듈 기반 → 불필요 드라이버 제거 → 빌드 시간 50% 절감 make localyesconfig → 모듈 대신 빌트인 전체 커버리지 테스트 make allyesconfig → 모든 옵션 활성화 → 빌드 30분~1시간+ → 컴파일 에러 검출용 make allmodconfig → 가능한 모든 것을 모듈로 ./scripts/config를 활용한 자동화 예시 ./scripts/config --enable DEBUG_INFO # 개별 옵션 활성화 ./scripts/config --disable MODULE_SIG # 개별 옵션 비활성화 ./scripts/config --set-val NR_CPUS 4 # 정수 값 설정 ./scripts/config --set-str LOCALVERSION "-mykernel" # 문자열 값 설정 ./scripts/config --module BTRFS_FS # 모듈로 설정 (=m) ./scripts/config --state DEBUG_INFO # 현재 상태 조회
그림: 커널 설정 전략 플로차트 - 목적에 따른 최적 설정 방법 선택

설정 프래그먼트 관리

프로젝트별 설정 변경을 .config 직접 수정 대신 프래그먼트 파일로 관리하면 버전 관리와 재현이 쉬워집니다.

# 디버그 프래그먼트: debug.config
cat > debug.config <<'EOF'
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_GDB_SCRIPTS=y
CONFIG_FRAME_POINTER=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_LOCKDEP=y
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_KASAN=y
EOF

# 프래그먼트 적용: defconfig + 디버그 옵션
cd /path/to/linux
make defconfig
./scripts/kconfig/merge_config.sh .config debug.config

# 또는 KCONFIG_ALLCONFIG 사용
make KCONFIG_ALLCONFIG=debug.config alldefconfig
# 최소 QEMU 부팅 프래그먼트: qemu-minimal.config
cat > qemu-minimal.config <<'EOF'
CONFIG_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM_VIRTIO=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_EXT4_FS=y
CONFIG_TMPFS=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
EOF
설정 관리 베스트 프랙티스:
  • 프래그먼트 파일을 Git에 커밋하여 팀과 공유
  • make savedefconfig로 현재 설정의 최소 diff를 defconfig로 저장
  • scripts/diffconfig로 두 .config 파일의 차이점만 추출
  • CI에서는 merge_config.sh로 베이스 + 프래그먼트 조합 자동화

참고자료

공식 문서

개발 도구

커뮤니티 및 학습 리소스