커널 개발 환경 설정
Linux 커널 개발을 위한 개발 환경 구축 가이드: 필수 도구 설치, 에디터 설정, QEMU/KVM 가상 환경, 크로스 컴파일, GDB/KGDB 디버거 설정까지 완벽 정리.
핵심 요약
- 필수 도구 — gcc, make, git, flex, bison, libelf-dev 등 빌드에 필수적인 패키지를 먼저 설치합니다.
- 개발 보조 도구 — ctags, cscope, clangd 등으로 코드 탐색과 자동완성을 강화합니다.
- 가상 환경 — QEMU/KVM으로 안전하게 커널을 테스트하고 디버깅합니다.
- 크로스 컴파일 — ARM, ARM64, RISC-V 등 다른 아키텍처용 커널을 빌드합니다.
- 디버거 설정 — GDB/KGDB로 커널 소스 레벨 디버깅을 수행합니다.
단계별 이해
- 도구 설치
배포판에 맞는 패키지 관리자로 필수 도구를 설치합니다. - 에디터 구성
선호하는 에디터에 코드 탐색 도구를 연동합니다. - 가상 환경 준비
QEMU/KVM으로 테스트용 가상 머신을 구성합니다. - 첫 빌드 실행
간단한 설정으로 커널을 빌드하고 부팅 테스트합니다. - 디버거 연동
GDB와 QEMU를 연결하여 커널 디버깅 환경을 완성합니다.
환경 설계 원칙
커널 개발 환경은 단순 설치보다 재현성, 격리, 검증 가능성이 중요합니다. 처음 한 번만 잘 구성하면 이후 실험 속도와 안정성이 크게 올라갑니다.
| 원칙 | 설명 | 실무 권장 |
|---|---|---|
| 재현성 | 같은 입력이면 같은 빌드 결과가 나와야 함 | 툴 버전 고정, 설정 파일(.config) 보관, 빌드 로그 아카이브 |
| 격리 | 호스트 시스템과 테스트 환경 분리 | QEMU/KVM 기본, 실제 장비는 후반 검증 단계에서만 사용 |
| 검증 가능성 | 문제 발생 시 원인 추적이 가능해야 함 | CONFIG_DEBUG_INFO, FRAME_POINTER, 로그 수집 자동화 |
| 점진적 확장 | 필수 도구부터 시작해 점진적으로 추가 | 필수(빌드) → 권장(탐색/가상화) → 선택(분석/자동화) |
개발 도구 의존성 로드맵
커널 개발 환경은 여러 도구들이 계층적으로 연결된 생태계입니다. 아래 다이어그램은 각 도구의 역할과 의존 관계를 보여주며, 환경 구축 순서를 안내합니다.
환경 구축 권장 순서:
- 최소 환경 (1~2시간): Layer 0-1 + QEMU → 간단한 커널 빌드/부팅 가능
- 기본 개발 (반나절): + Layer 2A/2B → 코드 탐색 및 가상머신 테스트
- 완전한 환경 (1일): + Layer 3 → 디버깅 및 분석까지 모든 작업 가능
- 전문가 환경 (지속): + Layer 4 → 다중 아키텍처 개발 및 자동화
디스크 공간: 커널 소스 3GB + 빌드 결과 10GB + 가상머신 이미지 5GB = 최소 20GB 여유 필요
필수 개발 도구 설치
Linux 커널 빌드를 위해서는 컴파일러, 빌드 시스템, 버전 관리 시스템, 그리고 다양한 유틸리티가 필요합니다. 배포판별로 패키지 이름이 다를 수 있으므로 각 배포판에 맞는 명령어를 사용하세요.
Ubuntu / Debian 계열
# 필수 빌드 도구
sudo apt update
sudo apt install -y build-essential \
gcc make git \
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에 필요dwarves: pahole 등 DWARF 디버깅 정보 분석 도구sparse: 정적 분석 도구ccache: 컴파일러 캐시로 재빌드 속도 향상
설치 직후 검증 명령
패키지 설치가 끝나면 바로 아래 명령으로 도구 상태를 확인하세요. 설치 자체보다 실행 가능한 상태를 검증하는 과정이 중요합니다.
# 필수 도구 버전 확인
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 빌드가 실패하면 컴파일러/링커/헤더 버전 조합을 우선 확인하세요.
버전 관리 정책
커널 개발에서는 "최신 버전"보다 "팀 전체에서 동일한 조합"이 더 중요할 때가 많습니다. 도구 버전을 팀 기준으로 고정하면 재현 불가 버그를 크게 줄일 수 있습니다.
- 컴파일러: GCC/Clang 메이저 버전을 팀 단위로 맞춥니다.
- 정적 분석 도구: sparse, coccinelle 버전 차이는 경고 양상 차이를 만듭니다.
- 디버거: GDB 버전 차이는 Python 스크립트 동작 차이로 이어질 수 있습니다.
- 문서화: 프로젝트 루트에 "권장 도구 버전 표"를 두고 신규 인원이 그대로 따라오게 합니다.
Fedora / RHEL / CentOS 계열
# 필수 빌드 도구
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y gcc make git \
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 \
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(Link Time Optimization) 등 GCC에 없는 보안/최적화 기능을 제공합니다.
LLVM/Clang 설치
# Ubuntu/Debian (LLVM 18 권장)
sudo apt install -y clang-18 lld-18 llvm-18
# Fedora
sudo dnf install -y clang lld llvm
# Arch Linux
sudo pacman -S clang lld 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)
# 특정 LLVM 버전 지정
make LLVM=-18 defconfig
make LLVM=-18 -j$(nproc)
# Clang으로 크로스 컴파일 (단일 바이너리로 모든 아키텍처)
make LLVM=1 ARCH=arm64 defconfig
make LLVM=1 ARCH=arm64 -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 구현 |
| Auto-init | CONFIG_INIT_STACK_ALL_ZERO |
스택 변수 자동 초기화 (정보 유출 방지) |
GCC vs Clang 비교
| 항목 | GCC | Clang/LLVM |
|---|---|---|
| 역사 | 커널 공식 기본 컴파일러 | 4.x부터 공식 지원, Android 커널 기본 |
| 에러 메시지 | 간결 | 상세하고 컬러풀, 제안 포함 |
| 경고 수준 | 보수적 | 더 많은 잠재 문제 감지 |
| 크로스 컴파일 | 아키텍처별 별도 툴체인 | 단일 바이너리로 모든 아키텍처 |
| LTO | 지원 (느림) | ThinLTO로 빠르고 효율적 |
| 보안 기능 | 기본 | CFI, Shadow Call Stack 등 추가 |
| 빌드 속도 | 보통 | 비슷하거나 약간 빠름 |
| 플러그인 | GCC 플러그인 지원 | 미지원 (대안 기능 제공) |
# 양쪽 컴파일러로 빌드 테스트
# 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)
코드 탐색 도구
대규모 커널 소스 코드를 효율적으로 탐색하려면 인덱싱 도구가 필수입니다. ctags, cscope, clangd 등을 사용하면 함수 정의 이동, 호출 계층 추적, 심볼 검색이 빠르게 가능합니다.
ctags & cscope
# Ubuntu/Debian
sudo apt install -y universal-ctags cscope
# Fedora/RHEL
sudo dnf install -y ctags cscope
# Arch Linux
sudo pacman -S ctags cscope
# 커널 소스 루트에서 인덱스 생성
cd /path/to/linux
make tags # ctags 생성
make cscope # cscope 생성
clangd (Language Server Protocol)
clangd는 LSP 프로토콜을 지원하는 현대적인 코드 인텔리전스 도구로, 자동완성, 정의 이동, 참조 찾기, 리팩토링 등을 제공합니다.
# Ubuntu/Debian (LLVM 14 이상 권장)
sudo apt install -y clangd-14
# Fedora/RHEL
sudo dnf install -y clang-tools-extra
# Arch Linux
sudo pacman -S clang
# 커널 소스에서 compile_commands.json 생성
cd /path/to/linux
make defconfig
./scripts/clang-tools/gen_compile_commands.py
compile_commands.json은 clangd가 프로젝트 구조를 이해하는 데 사용하는 컴파일 데이터베이스입니다. 커널 설정을 변경할 때마다 재생성하세요.
인덱스 갱신 전략
커널 소스는 변경량이 크기 때문에 인덱스를 한 번만 생성하면 금방 오래된 정보가 됩니다. 다음 규칙으로 관리하면 탐색 정확도가 유지됩니다.
- 브랜치 전환 직후:
make tags cscope재생성 - .config 변경 후:
gen_compile_commands.py재실행 - 대규모 리베이스 후: 인덱스 파일 삭제 후 전체 재생성
# 안전한 인덱스 재생성 루틴
rm -f tags cscope.out cscope.in.out cscope.po.out compile_commands.json
make tags cscope
./scripts/clang-tools/gen_compile_commands.py
rg로 먼저 텍스트 맥락을 보고, 이후 ctags/cscope/clangd로 정확한 정의로 이동하면 탐색 속도가 안정적입니다.
에디터 설정
Vim
Vim은 커널 개발자들 사이에서 가장 인기 있는 에디터 중 하나입니다. cscope와 ctags를 통합하여 강력한 코드 탐색 환경을 구축할 수 있습니다.
.vimrc 설정 예제
" ~/.vimrc
" ===== 기본 설정 =====
set number " 행번호 표시
set relativenumber " 상대 행번호
set tabstop=8 " 탭 너비 (커널 코딩 스타일)
set shiftwidth=8 " 인덴트 너비
set noexpandtab " 탭을 스페이스로 변환 안 함
set autoindent
set smartindent
set hlsearch " 검색 결과 하이라이트
set incsearch " 증분 검색
" ===== ctags 설정 =====
set tags=./tags,tags; " 상위 디렉토리까지 tags 파일 검색
" ===== cscope 설정 =====
if has("cscope")
set csprg=/usr/bin/cscope
set csto=0
set cst
set nocsverb
" cscope.out 자동 로드
if filereadable("cscope.out")
cs add cscope.out
endif
set csverb
endif
" ===== cscope 키 바인딩 =====
nmap <C-\>s :cs find s <C-R>=expand("<cword>")<CR><CR> " 심볼 찾기
nmap <C-\>g :cs find g <C-R>=expand("<cword>")<CR><CR> " 정의 찾기
nmap <C-\>c :cs find c <C-R>=expand("<cword>")<CR><CR> " 호출 찾기
nmap <C-\>t :cs find t <C-R>=expand("<cword>")<CR><CR> " 텍스트 찾기
" ===== 커널 코딩 스타일 =====
autocmd FileType c,cpp setlocal cindent cinoptions=:0,l1,g0,(0,W4
Visual Studio Code
VS Code는 풍부한 확장 생태계와 직관적인 UI를 제공합니다. clangd 확장을 사용하면 강력한 인텔리센스를 활용할 수 있습니다.
필수 확장 설치
- C/C++ (Microsoft): 기본 C/C++ 지원
- clangd: LSP 기반 인텔리센스 (C/C++ 확장과 충돌 방지 설정 필요)
- Kernel Dev: 커널 개발 전용 스니펫과 도구
- GitLens: Git 이력 탐색
settings.json 설정
{
"editor.tabSize": 8,
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"editor.rulers": [80, 100],
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
// clangd 설정
"clangd.path": "/usr/bin/clangd-14",
"clangd.arguments": [
"--background-index",
"--clang-tidy",
"--completion-style=detailed",
"--header-insertion=never"
],
// C/C++ 확장 IntelliSense 비활성화 (clangd와 충돌 방지)
"C_Cpp.intelliSenseEngine": "Disabled"
}
Emacs
Emacs는 오랜 역사를 가진 강력한 에디터로, 커널 개발에 최적화된 다양한 모드를 제공합니다.
;; ~/.emacs.d/init.el
;; ===== 기본 설정 =====
(setq-default indent-tabs-mode t)
(setq-default tab-width 8)
(setq c-basic-offset 8)
;; ===== 커널 코딩 스타일 =====
(defun linux-kernel-coding-style ()
(setq c-indent-level 8
c-brace-imaginary-offset 0
c-brace-offset -8
c-argdecl-indent 8
c-label-offset -8
c-continued-statement-offset 8
indent-tabs-mode t
tab-width 8))
(add-hook 'c-mode-hook 'linux-kernel-coding-style)
;; ===== cscope 설정 =====
(require 'xcscope)
(cscope-setup)
;; ===== lsp-mode (clangd) =====
(use-package lsp-mode
:hook (c-mode . lsp-deferred)
:commands (lsp lsp-deferred)
:config
(setq lsp-clients-clangd-args
'("--background-index"
"--clang-tidy"
"--completion-style=detailed")))
Neovim (현대적 Vim)
Neovim은 Vim의 현대적 포크로, 내장 LSP 클라이언트, Lua 설정, treesitter 구문 강조 등 커널 개발에 유용한 기능을 기본 제공합니다.
# Ubuntu/Debian (최신 버전)
sudo add-apt-repository ppa:neovim-ppa/unstable
sudo apt install neovim
# Fedora
sudo dnf install neovim
# Arch Linux
sudo pacman -S neovim
-- ~/.config/nvim/init.lua
-- ===== 기본 설정 (커널 코딩 스타일) =====
vim.opt.tabstop = 8
vim.opt.shiftwidth = 8
vim.opt.expandtab = false
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.colorcolumn = "80,100"
vim.opt.signcolumn = "yes"
-- ===== 내장 LSP 설정 (clangd) =====
vim.lsp.start({
name = "clangd",
cmd = { "clangd",
"--background-index",
"--clang-tidy",
"--completion-style=detailed",
"--header-insertion=never",
"-j=4",
},
root_dir = vim.fs.dirname(
vim.fs.find({"compile_commands.json", "Makefile"}, { upward = true })[1]
),
})
-- ===== LSP 키 바인딩 =====
vim.keymap.set("n", "gd", vim.lsp.buf.definition)
vim.keymap.set("n", "gr", vim.lsp.buf.references)
vim.keymap.set("n", "K", vim.lsp.buf.hover)
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename)
-- ===== ctags/cscope 호환 =====
vim.opt.tags = "./tags,tags;"
-- ===== 진단 표시 =====
vim.diagnostic.config({
virtual_text = true,
signs = true,
underline = true,
})
- Vim: 가벼움, 어디서나 사용 가능, 서버 환경 기본 탑재
- Neovim: Lua 설정, 내장 LSP, treesitter 기본 제공, 현대적 플러그인 생태계
- VS Code: GUI 기반, 직관적 디버깅, Remote-SSH로 원격 개발 우수
- Emacs: 강력한 커스터마이징, Org-mode, TRAMP(원격 편집)
핵심은 에디터 자체보다 clangd + compile_commands.json 조합입니다. 이것만 설정되면 어떤 에디터든 동일한 코드 인텔리전스를 제공합니다.
QEMU/KVM 가상 환경 설정
실제 하드웨어에서 커널을 테스트하는 것은 위험하므로, QEMU/KVM 가상 머신을 사용하면 안전하게 커널을 부팅하고 디버깅할 수 있습니다.
QEMU 설치
# Ubuntu/Debian
sudo apt install -y qemu-system-x86 qemu-system-arm qemu-system-aarch64 \
qemu-utils libvirt-daemon-system virt-manager
# Fedora/RHEL
sudo dnf install -y qemu-kvm qemu-img libvirt virt-manager
# Arch Linux
sudo pacman -S qemu qemu-arch-extra libvirt virt-manager
# 현재 사용자를 libvirt, kvm 그룹에 추가
sudo usermod -aG libvirt,kvm $USER
newgrp libvirt
최소 루트 파일시스템 생성
# Buildroot로 간단한 rootfs 생성
git clone https://git.buildroot.net/buildroot
cd buildroot
make qemu_x86_64_defconfig
make menuconfig
# Filesystem images -> ext4 선택
make -j$(nproc)
# 생성된 이미지: output/images/rootfs.ext4
QEMU로 커널 부팅
# 커널 빌드
cd /path/to/linux
make x86_64_defconfig
# 디버깅을 위해 CONFIG_DEBUG_INFO, CONFIG_GDB_SCRIPTS 활성화
./scripts/config --enable DEBUG_INFO
./scripts/config --enable GDB_SCRIPTS
./scripts/config --enable DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
make -j$(nproc)
# QEMU로 부팅 (직렬 콘솔 출력)
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-hda /path/to/rootfs.ext4 \
-append "root=/dev/sda rw console=ttyS0" \
-nographic \
-enable-kvm \
-m 2G \
-smp 2
-kernel: 부팅할 커널 이미지-hda: 루트 파일시스템 이미지-append: 커널 부트 파라미터-nographic: 그래픽 없이 직렬 콘솔만 사용-enable-kvm: KVM 가속 활성화 (훨씬 빠름)-m: 메모리 크기-smp: CPU 코어 수
빠른 테스트 루프 구성
커널 개발 효율은 "수정 후 부팅까지 걸리는 시간"에 크게 좌우됩니다. 아래 루프는 빌드와 부팅 반복 시간을 줄이는 기본 패턴입니다.
- 초기 full build: 전체 빌드로 기준 이미지 생성
- 이후 incremental build: 변경 범위만 재컴파일
- 직렬 콘솔 부팅: GUI 없이 즉시 로그 확인
- 실패 시 로그 캡처: 다음 수정에 바로 반영
# 빠른 반복 실행 예시
make -j$(nproc)
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-hda /path/to/rootfs.ext4 \
-append "root=/dev/sda rw console=ttyS0 panic=-1" \
-nographic -enable-kvm -m 2G -smp 2 \
| tee qemu-boot.log
자주 발생하는 부팅 실패와 대응
| 증상 | 원인 후보 | 대응 |
|---|---|---|
| VFS panic: unable to mount root fs | 루트 디바이스 경로/드라이버 불일치 | root= 파라미터와 저장장치 드라이버 설정 재확인 |
| 부팅 즉시 재시작 | 초기 패닉 후 자동 재부팅 | panic=-1로 정지시켜 로그 확인 |
| 콘솔 출력 없음 | 콘솔 장치 지정 불일치 | console=ttyS0 또는 아키텍처별 직렬 장치 재검토 |
| KVM 사용 불가 | 가상화 미활성 또는 권한 부족 | /dev/kvm 권한, BIOS 가상화 옵션 점검 |
virtme-ng: 빠른 커널 테스트
virtme-ng는 별도의 rootfs 이미지 없이 호스트 파일시스템을 직접 공유하여 빌드한 커널을 즉시 부팅하는 도구입니다. 전통적인 QEMU + rootfs 방식보다 설정이 간단하고 반복 속도가 훨씬 빠릅니다.
virtme-ng 설치
# pip로 설치
pip3 install virtme-ng
# 또는 소스에서 설치
git clone https://github.com/arighi/virtme-ng.git
cd virtme-ng
pip3 install .
# QEMU 필요 (이미 설치되어 있다면 생략)
sudo apt install qemu-system-x86
기본 사용법
# 커널 소스 디렉토리에서
cd /path/to/linux
# 빌드 + 부팅 한 번에 (가장 빠른 방법)
vng --build --run
# 빌드만
vng --build
# 이미 빌드된 커널로 부팅
vng --run
# 커널 설정 + 빌드 + 부팅
vng --build --run --config defconfig
# 추가 커널 파라미터
vng --run --append "debug loglevel=8"
# 특정 명령 실행 후 종료
vng --run --exec "uname -r && cat /proc/version"
# GDB 디버깅 모드
vng --run --gdb
# 다른 터미널에서: gdb vmlinux -ex "target remote :1234"
# 네트워크 활성화
vng --run --net user
# CPU/메모리 설정
vng --run --cpus 4 --memory 4G
virtme-ng vs 전통 QEMU 비교
| 항목 | 전통 QEMU + rootfs | virtme-ng |
|---|---|---|
| rootfs 준비 | Buildroot/debootstrap으로 별도 생성 | 호스트 파일시스템 공유 (준비 불요) |
| 첫 부팅까지 시간 | rootfs 생성 30분+ 빌드 5분+ | 빌드 후 즉시 (~15초) |
| 호스트 도구 사용 | rootfs에 별도 설치 필요 | 호스트 도구 그대로 사용 |
| 커널 모듈 테스트 | rootfs에 모듈 복사 필요 | 자동으로 모듈 경로 공유 |
| 격리 수준 | 완전 격리 | 호스트 FS 읽기 전용 공유 |
| 네트워크 테스트 | 전체 네트워크 스택 테스트 가능 | 기본적 네트워크 테스트 가능 |
| 적합한 용도 | 종합 테스트, 배포 검증 | 빠른 반복 개발, 기능 검증 |
initramfs 직접 생성
initramfs는 커널이 부팅 초기에 사용하는 메모리 기반 루트 파일시스템입니다. BusyBox를 사용하면 최소한의 크기로 기능적인 initramfs를 만들 수 있어, 별도 디스크 이미지 없이 빠른 부팅 테스트가 가능합니다.
BusyBox 기반 initramfs
# 1. BusyBox 다운로드 & 정적 빌드
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
make defconfig
# 정적 링크 활성화 (중요!)
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
make -j$(nproc)
make install # _install/ 에 설치됨
# 2. initramfs 디렉토리 구성
mkdir -p /tmp/initramfs
cd /tmp/initramfs
# BusyBox 바이너리 복사
cp -a /path/to/busybox-1.36.1/_install/* .
# 필수 디렉토리 생성
mkdir -p proc sys dev etc tmp run var/log
# 3. init 스크립트 생성
cat > init <<'INIT_EOF'
#!/bin/sh
echo "=== initramfs booting ==="
# 가상 파일시스템 마운트
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
# 커널 정보 출력
echo "Kernel: $(uname -r)"
echo "Arch: $(uname -m)"
# 네트워크 (선택)
ip link set lo up 2>/dev/null
# 셸 실행
echo "=== Dropping to shell ==="
exec /bin/sh
INIT_EOF
chmod +x init
# 4. initramfs cpio 아카이브 생성
find . | cpio -o -H newc | gzip > /tmp/initramfs.cpio.gz
# 5. QEMU로 부팅 테스트
qemu-system-x86_64 \
-kernel /path/to/linux/arch/x86/boot/bzImage \
-initrd /tmp/initramfs.cpio.gz \
-append "console=ttyS0 rdinit=/init" \
-nographic -enable-kvm -m 1G
커널 내장 initramfs
# 커널 설정에서 initramfs 경로 지정
./scripts/config --enable BLK_DEV_INITRD
./scripts/config --set-str INITRAMFS_SOURCE "/tmp/initramfs"
# 빌드하면 initramfs가 커널에 내장됨
make -j$(nproc)
# 별도 -initrd 없이 부팅 가능
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-append "console=ttyS0" \
-nographic -enable-kvm -m 1G
고급 initramfs 구성
# 커널 모듈을 initramfs에 포함
cd /path/to/linux
make modules_install INSTALL_MOD_PATH=/tmp/initramfs
# 테스트용 커스텀 프로그램 추가
cat > /tmp/test_module.c <<'EOF'
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void) {
pr_info("Hello from initramfs!\n");
return 0;
}
static void __exit hello_exit(void) {
pr_info("Goodbye!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
EOF
# init 스크립트에 모듈 로드 추가
# insmod /lib/modules/$(uname -r)/hello.ko
- initramfs: 빠른 부팅 테스트, 모듈 로드 테스트, 드라이버 초기화 검증
- Buildroot rootfs: 네트워크 테스트, 사용자 공간 연동, 장시간 스트레스 테스트
- Debian rootfs: 완전한 사용자 환경, 패키지 설치, 종합 시스템 테스트
- virtme-ng: 호스트 FS 공유, 가장 빠른 반복 주기, 일상 개발
크로스 컴파일 환경
x86_64 호스트에서 ARM, ARM64, RISC-V 등 다른 아키텍처용 커널을 빌드하려면 크로스 컴파일 툴체인이 필요합니다.
크로스 컴파일러 설치
# Ubuntu/Debian
sudo apt install -y \
gcc-arm-linux-gnueabi \
gcc-arm-linux-gnueabihf \
gcc-aarch64-linux-gnu \
gcc-riscv64-linux-gnu
# Fedora/RHEL
sudo dnf install -y \
gcc-arm-linux-gnu \
gcc-aarch64-linux-gnu \
gcc-riscv64-linux-gnu
# Arch Linux
sudo pacman -S \
arm-none-eabi-gcc \
aarch64-linux-gnu-gcc
크로스 컴파일 빌드
# ARM (32-bit)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- multi_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)
# ARM64 (64-bit)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
# RISC-V (64-bit)
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
크로스 컴파일 커널 QEMU 부팅
# ARM64 커널 QEMU 부팅
qemu-system-aarch64 \
-M virt \
-cpu cortex-a57 \
-kernel arch/arm64/boot/Image \
-append "console=ttyAMA0" \
-nographic \
-m 2G
# RISC-V 커널 QEMU 부팅
qemu-system-riscv64 \
-M virt \
-kernel arch/riscv/boot/Image \
-append "console=ttyS0" \
-nographic \
-m 2G
크로스 컴파일 검증 체크리스트
크로스 컴파일된 커널이 제대로 빌드되고 동작하는지 체계적으로 검증하는 것이 중요합니다. 아래 체크리스트는 빌드부터 부팅 검증까지 전체 과정을 안내합니다.
| 아키텍처 | ARCH 변수 | 툴체인 접두사 | QEMU 시스템 | 커널 이미지 경로 |
|---|---|---|---|---|
| ARM (32-bit) | arm |
arm-linux-gnueabihf- |
qemu-system-arm |
arch/arm/boot/zImage |
| ARM64 (64-bit) | arm64 |
aarch64-linux-gnu- |
qemu-system-aarch64 |
arch/arm64/boot/Image |
| RISC-V (64-bit) | riscv |
riscv64-linux-gnu- |
qemu-system-riscv64 |
arch/riscv/boot/Image |
| PowerPC (64-bit) | powerpc |
powerpc64-linux-gnu- |
qemu-system-ppc64 |
arch/powerpc/boot/vmlinux |
| MIPS (32-bit) | mips |
mips-linux-gnu- |
qemu-system-mips |
arch/mips/boot/vmlinux |
크로스 컴파일 문제 해결:
- 빌드 실패:
ARCH와CROSS_COMPILE이 모든 make 명령에 포함되었는지 확인 - QEMU 부팅 실패:
-M옵션으로 올바른 머신 타입 지정 (예:-M virt) - 심볼 누락:
CONFIG_DEBUG_INFO활성화 후 재빌드 - 모듈 로드 실패: 커널 버전과 모듈 빌드 환경이 일치하는지 확인
- 환경 변수 설정: Makefile에
export ARCH=arm64,export CROSS_COMPILE=...추가
크로스 컴파일 사전 점검 루틴
크로스 빌드 실패의 다수는 소스 문제가 아니라 툴체인/환경 변수 불일치에서 발생합니다. 아래 순서를 먼저 실행하면 실패 원인을 빠르게 분리할 수 있습니다.
# 1) 툴체인 확인
which aarch64-linux-gnu-gcc
aarch64-linux-gnu-gcc -dumpmachine
# 2) 환경 변수 확인
echo "ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE"
# 3) 산출물 아키텍처 확인
file arch/arm64/boot/Image
readelf -h vmlinux | grep "Machine"
ARCH, CROSS_COMPILE 값이 달라지면 재현이 어렵습니다.
프로젝트별 쉘 스크립트(env-arm64.sh 등)로 환경을 고정하는 방식을 권장합니다.
GDB/KGDB 디버거 설정
GDB를 사용하면 QEMU 가상 머신에서 실행 중인 커널을 소스 레벨에서 디버깅할 수 있습니다. 브레이크포인트 설정, 스택 추적, 변수 검사 등이 가능합니다.
커널 GDB 디버깅 환경 구성
# 커널 설정에서 디버깅 옵션 활성화
cd /path/to/linux
./scripts/config --enable DEBUG_INFO
./scripts/config --enable DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
./scripts/config --enable GDB_SCRIPTS
./scripts/config --enable FRAME_POINTER
./scripts/config --disable DEBUG_INFO_REDUCED
make olddefconfig
make -j$(nproc)
# QEMU를 GDB 서버 모드로 실행 (1234 포트 대기)
qemu-system-x86_64 \
-kernel arch/x86/boot/bzImage \
-hda /path/to/rootfs.ext4 \
-append "root=/dev/sda rw console=ttyS0 nokaslr" \
-nographic \
-s -S \
-m 2G \
-smp 2
# 다른 터미널에서 GDB 실행
gdb vmlinux
-s: TCP 1234 포트에서 GDB 서버 시작 (-gdb tcp::1234와 동일)-S: 시작 시 CPU를 일시 정지 (GDB 연결 대기)nokaslr: KASLR 비활성화 (주소 고정으로 디버깅 용이)
GDB 명령어 예제
# GDB 프롬프트에서
# QEMU에 연결
(gdb) target remote :1234
# 커널 GDB 스크립트 로드 (선택, 자동 로드되지 않는 경우)
(gdb) source vmlinux-gdb.py
# 브레이크포인트 설정
(gdb) break start_kernel
(gdb) break do_sys_open
# 실행 계속
(gdb) continue
# 스택 추적
(gdb) backtrace
# 변수 출력
(gdb) print init_task
# 구조체 필드 출력
(gdb) print init_task.comm
# 메모리 덤프
(gdb) x/10x 0xffffffff81000000
# 커널 전용 명령 (vmlinux-gdb.py 제공)
(gdb) lx-dmesg # 커널 로그 출력
(gdb) lx-lsmod # 로드된 모듈 목록
(gdb) lx-ps # 프로세스 목록
QEMU-GDB 통합 워크플로
QEMU와 GDB를 연동한 커널 디버깅은 여러 단계를 거칩니다. 아래 다이어그램은 빌드부터 디버깅까지 전체 흐름을 보여줍니다.
QEMU-GDB 디버깅 체크리스트:
- 커널 설정에서
CONFIG_DEBUG_INFO,CONFIG_GDB_SCRIPTS활성화 - 부팅 옵션에
nokaslr추가 (주소 고정) - QEMU를
-s -S옵션으로 시작 (GDB 대기) - GDB에서
vmlinux로드 (bzImage가 아님!) target remote :1234로 QEMU 연결- 브레이크포인트 설정 후
continue
주의: vmlinux는 디버그 심볼이 포함된 ELF 파일이고, bzImage는 압축된 부팅 이미지입니다. GDB에는 vmlinux를 사용해야 합니다.
KGDB (실제 하드웨어 디버깅)
KGDB는 실제 하드웨어에서 직렬 포트나 네트워크를 통해 커널을 디버깅할 수 있게 해줍니다.
# 커널 설정
./scripts/config --enable KGDB
./scripts/config --enable KGDB_SERIAL_CONSOLE
./scripts/config --enable KGDB_KDB
make olddefconfig
make -j$(nproc)
# 부트 파라미터에 KGDB 옵션 추가
# kgdboc=ttyS0,115200 kgdbwait
첫 디버깅 세션 권장 시나리오
처음에는 복잡한 경로 대신 부팅 초기 경로 하나만 추적하는 방식이 가장 학습 효율이 좋습니다.
start_kernel브레이크포인트 설정continue후 진입 확인bt로 초기 콜스택 확인next/step으로 서브시스템 초기화 흐름 파악- 관찰 결과를 텍스트로 기록해 다음 세션 기준점으로 사용
(gdb) target remote :1234
(gdb) break start_kernel
(gdb) continue
(gdb) bt
(gdb) next
(gdb) list
디버그 커널 설정 옵션 총정리
커널에는 수백 개의 디버깅 관련 설정 옵션이 있습니다. 목적에 맞는 옵션을 선택적으로 활성화하면 디버깅 효율이 크게 향상됩니다. 주요 옵션을 카테고리별로 정리합니다.
디버그 정보 옵션
| 설정 옵션 | 기능 | 오버헤드 | 용도 |
|---|---|---|---|
CONFIG_DEBUG_INFO |
DWARF 디버그 정보 포함 | vmlinux 크기 5~10배 증가 | GDB 디버깅 필수 |
CONFIG_DEBUG_INFO_DWARF5 |
DWARF v5 형식 사용 | DWARF4 대비 크기 절감 | 최신 GDB/LLVM 권장 |
CONFIG_GDB_SCRIPTS |
커널 GDB Python 스크립트 | 없음 | lx-dmesg, lx-ps 등 사용 |
CONFIG_FRAME_POINTER |
프레임 포인터 유지 | 성능 1~2% 감소 | 정확한 스택 추적 |
CONFIG_DEBUG_INFO_BTF |
BPF Type Format 생성 | 빌드 시간 약간 증가 | BPF/bpftrace 필수 |
CONFIG_KALLSYMS_ALL |
모든 심볼을 /proc/kallsyms에 | 커널 크기 약간 증가 | perf, ftrace 심볼 해석 |
메모리 디버깅 옵션
| 설정 옵션 | 기능 | 오버헤드 | 검출 대상 |
|---|---|---|---|
CONFIG_KASAN |
Kernel Address Sanitizer | 메모리 3~5배, 성능 50% 감소 | use-after-free, buffer overflow |
CONFIG_KASAN_GENERIC |
KASAN 일반 모드 | 가장 정확, 가장 느림 | 개발 중 전면 검사 |
CONFIG_KASAN_SW_TAGS |
KASAN 소프트웨어 태그 모드 | 중간 오버헤드 (ARM64) | ARM64 전용 경량 검사 |
CONFIG_KMSAN |
Kernel Memory Sanitizer | 큰 오버헤드 | 초기화되지 않은 메모리 사용 |
CONFIG_KFENCE |
Kernel Electric Fence | 거의 없음 (샘플링) | 프로덕션 환경 메모리 버그 |
CONFIG_SLUB_DEBUG |
SLUB 할당자 디버깅 | 약간의 성능 감소 | slab corruption, 이중 해제 |
CONFIG_DEBUG_PAGEALLOC |
페이지 해제 시 언매핑 | 큰 성능 감소 | use-after-free (페이지 레벨) |
CONFIG_DEBUG_SLAB |
SLAB 포이즌/레드존 | 성능 감소 | slab 오버런, corruption |
동기화/락 디버깅 옵션
| 설정 옵션 | 기능 | 검출 대상 |
|---|---|---|
CONFIG_LOCKDEP |
락 의존성 추적 | 데드락, 순환 의존성, 잘못된 락 순서 |
CONFIG_PROVE_LOCKING |
락 정확성 증명 | 런타임에 락 규칙 위반 감지 |
CONFIG_LOCK_STAT |
락 통계 수집 | /proc/lock_stat으로 경합 분석 |
CONFIG_DEBUG_MUTEXES |
뮤텍스 디버깅 | 잘못된 뮤텍스 사용 (재귀 등) |
CONFIG_DEBUG_SPINLOCK |
스핀락 디버깅 | 초기화되지 않은 스핀락 사용 |
CONFIG_DEBUG_RWSEMS |
RW 세마포어 디버깅 | 잘못된 rw_semaphore 사용 |
CONFIG_DEBUG_ATOMIC_SLEEP |
원자 컨텍스트 sleep 감지 | 인터럽트/스핀락 중 sleep 호출 |
CONFIG_DETECT_HUNG_TASK |
행 태스크 감지 | 120초 이상 TASK_UNINTERRUPTIBLE |
CONFIG_WW_MUTEX_SELFTEST |
Wait/Wound 뮤텍스 셀프테스트 | 부팅 시 ww_mutex 정확성 검증 |
기타 디버깅 옵션
| 설정 옵션 | 기능 | 용도 |
|---|---|---|
CONFIG_DYNAMIC_DEBUG |
pr_debug() 동적 활성화 | 런타임에 선택적 디버그 로그 on/off |
CONFIG_DEBUG_FS |
debugfs 파일시스템 | 커널 내부 상태 노출 (/sys/kernel/debug) |
CONFIG_MAGIC_SYSRQ |
SysRq 키 | 시스템 행 시 긴급 동작 (sync, 리부트 등) |
CONFIG_PANIC_ON_OOPS |
Oops 시 패닉 | Oops 발생 즉시 정지 (디버깅용) |
CONFIG_SOFTLOCKUP_DETECTOR |
소프트 락업 감지 | CPU가 오래 선점 불가 상태 |
CONFIG_HARDLOCKUP_DETECTOR |
하드 락업 감지 | CPU가 인터럽트도 처리 못함 |
CONFIG_UBSAN |
Undefined Behavior Sanitizer | 정수 오버플로, 배열 인덱스 초과 |
CONFIG_KCSAN |
Kernel Concurrency Sanitizer | 데이터 레이스 감지 |
CONFIG_FTRACE |
함수 추적 인프라 | 함수 호출 추적, 이벤트 트레이싱 |
CONFIG_FUNCTION_TRACER |
함수 호출 추적기 | 모든 함수 진입/종료 기록 |
목적별 디버그 프로필
# 프로필 1: 기본 디버깅 (GDB + 로그)
./scripts/config --enable DEBUG_INFO
./scripts/config --enable DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
./scripts/config --enable GDB_SCRIPTS
./scripts/config --enable FRAME_POINTER
./scripts/config --enable DYNAMIC_DEBUG
./scripts/config --enable DEBUG_FS
./scripts/config --enable MAGIC_SYSRQ
# 프로필 2: 메모리 버그 헌팅
./scripts/config --enable KASAN
./scripts/config --enable KASAN_GENERIC
./scripts/config --enable KFENCE
./scripts/config --enable SLUB_DEBUG
./scripts/config --enable DEBUG_PAGEALLOC
./scripts/config --enable PAGE_OWNER
# 프로필 3: 동기화 버그 헌팅
./scripts/config --enable LOCKDEP
./scripts/config --enable PROVE_LOCKING
./scripts/config --enable DEBUG_MUTEXES
./scripts/config --enable DEBUG_SPINLOCK
./scripts/config --enable DEBUG_ATOMIC_SLEEP
./scripts/config --enable DETECT_HUNG_TASK
./scripts/config --enable KCSAN
# 프로필 4: 성능 분석
./scripts/config --enable FTRACE
./scripts/config --enable FUNCTION_TRACER
./scripts/config --enable FUNCTION_GRAPH_TRACER
./scripts/config --enable KALLSYMS_ALL
./scripts/config --enable DEBUG_INFO_BTF
# 적용
make olddefconfig
ftrace/perf 기본 설정
ftrace와 perf는 커널 성능 분석과 동작 추적의 핵심 도구입니다. 커널 설정에서 관련 옵션을 활성화하고 기본 사용법을 익혀두면 디버깅 효율이 크게 향상됩니다.
ftrace 기본 사용
# 커널 설정 (필수)
./scripts/config --enable FTRACE
./scripts/config --enable FUNCTION_TRACER
./scripts/config --enable FUNCTION_GRAPH_TRACER
./scripts/config --enable DYNAMIC_FTRACE
./scripts/config --enable STACK_TRACER
# ftrace 기본 사용 (debugfs 마운트 필요)
mount -t debugfs nodev /sys/kernel/debug
# 사용 가능한 트레이서 확인
cat /sys/kernel/debug/tracing/available_tracers
# 함수 트레이서 활성화
echo function > /sys/kernel/debug/tracing/current_tracer
# 특정 함수만 추적
echo "do_sys_openat2" > /sys/kernel/debug/tracing/set_ftrace_filter
# 추적 시작/중지
echo 1 > /sys/kernel/debug/tracing/tracing_on
# ... 작업 수행 ...
echo 0 > /sys/kernel/debug/tracing/tracing_on
# 결과 확인
cat /sys/kernel/debug/tracing/trace
# function_graph 트레이서 (호출 깊이 표시)
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo "tcp_sendmsg" > /sys/kernel/debug/tracing/set_graph_function
echo 1 > /sys/kernel/debug/tracing/tracing_on
trace-cmd 사용
# trace-cmd 설치
sudo apt install trace-cmd
# 함수 추적 녹화
trace-cmd record -p function -l "do_sys_*"
# Ctrl+C로 중지
# 결과 보기
trace-cmd report | head -50
# function_graph 녹화
trace-cmd record -p function_graph -g tcp_sendmsg
# 이벤트 추적 (스케줄러)
trace-cmd record -e sched_switch -e sched_wakeup
trace-cmd report
perf 기본 사용
# perf 설치
sudo apt install linux-tools-common linux-tools-$(uname -r)
# 또는 커널 소스에서 빌드
make -C tools/perf install
# CPU 프로파일링 (10초간 시스템 전체)
perf record -a -g -- sleep 10
perf report
# 특정 프로세스 프로파일링
perf record -g -p $PID -- sleep 10
# 하드웨어 이벤트 카운터
perf stat -e cycles,instructions,cache-misses,branch-misses -- make -j$(nproc)
# 콜 그래프 시각화 (Flamegraph)
perf record -a -g -- sleep 30
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
# 커널 함수 프로파일링
perf top -e cycles:k # 커널 모드만
- ftrace: 함수 호출 순서, 실행 시간, 특정 경로 추적 → "이 함수가 언제 어떤 순서로 호출되나?"
- perf: 통계적 프로파일링, 핫스팟 분석, 하드웨어 카운터 → "어디서 CPU 시간을 가장 많이 쓰나?"
- bpftrace: 유연한 동적 추적, 커스텀 집계 → "특정 조건에서 특정 값 분포는?"
- trace-cmd: ftrace의 사용자 친화적 프론트엔드 → "ftrace를 쉽게 쓰고 싶다"
빌드 속도 최적화
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
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
병렬 작업 수 최적화
# 기본: 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 |
매크로 전개 결과 확인 |
| 어셈블리 확인 | make drivers/net/my_driver.s |
컴파일러 출력 코드 확인 |
정적 분석 도구
Sparse
Sparse는 Linux 커널 전용 정적 분석 도구로, 타입 체크, 엔디안 검증, 락 검증 등을 수행합니다.
# Sparse로 검사하며 빌드
make C=1 -j$(nproc) # 변경된 파일만
make C=2 -j$(nproc) # 모든 파일
Coccinelle
Coccinelle은 의미론적 패치 언어(SmPL)를 사용하여 C 코드를 자동 변환하고 버그를 찾습니다.
# Ubuntu/Debian
sudo apt install coccinelle
# 커널 소스에서 Coccinelle 검사 실행
make coccicheck MODE=report
checkpatch.pl 상세 사용법
checkpatch.pl은 커널 코딩 스타일(Documentation/process/coding-style.rst)을 자동 검사하는 필수 도구입니다. 업스트림 패치 제출 전에 반드시 통과해야 합니다.
# 파일 직접 검사
./scripts/checkpatch.pl --file drivers/net/my_driver.c
# 패치 파일 검사
./scripts/checkpatch.pl 0001-my-patch.patch
# 마지막 커밋 검사
git diff HEAD~1 | ./scripts/checkpatch.pl -
# 마지막 N개 커밋 각각 검사
git format-patch -3 --stdout | ./scripts/checkpatch.pl
# 엄격 모드 (추가 경고 포함)
./scripts/checkpatch.pl --strict --file drivers/net/my_driver.c
# 특정 검사 항목 무시
./scripts/checkpatch.pl --ignore LONG_LINE,TRAILING_WHITESPACE --file my_file.c
# 사용 가능한 검사 항목 목록
./scripts/checkpatch.pl --list-types
| 검사 유형 | 심각도 | 설명 | 예시 |
|---|---|---|---|
| ERROR | 필수 수정 | 코딩 스타일 위반 | 탭 대신 스페이스, 잘못된 중괄호 위치 |
| WARNING | 강력 권고 | 잠재적 문제 | 80자 초과, 불필요한 초기화 |
| CHECK | 참고 | 스타일 제안 | 주석 형식, 정렬 권장 |
TRAILING_WHITESPACE: 줄 끝 공백 → 에디터에서 자동 제거 설정SPACING:if(→if (,for(→for (OPEN_BRACE: 함수 정의 중괄호는 다음 줄, 제어문은 같은 줄LONG_LINE: 80자 권장, 100자 이내 유지 (문자열 리터럴 예외)SPLIT_STRING: 로그 메시지 문자열은 가독성을 위해 분할하지 않음UNNECESSARY_ELSE: if 블록이 return으로 끝나면 else 불필요
커널 셀프테스트 (kselftest)
커널 셀프테스트는 커널 기능의 회귀를 자동으로 검출하는 테스트 프레임워크입니다. tools/testing/selftests/에 서브시스템별 테스트가 있으며, 패치 제출 전 관련 테스트를 실행하는 것이 좋습니다.
셀프테스트 실행
# 전체 셀프테스트 빌드 & 실행
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 |
메모리 관리 | CONFIG_USERFAULTFD |
cgroup |
컨트롤 그룹 | CONFIG_CGROUPS |
futex |
Futex 동기화 | CONFIG_FUTEX |
seccomp |
Seccomp 필터 | CONFIG_SECCOMP |
kvm |
KVM 가상화 | CONFIG_KVM |
filesystems |
파일시스템 공통 | 다양한 FS CONFIG |
테스트 작성 기본 패턴
// 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
KSFT_SKIP반환으로 선행 조건 미충족 시 테스트 건너뛰기make -C tools/testing/selftests TARGETS="net" summary=1로 결과 요약- QEMU에서 실행 시
INSTALL_PATH로 rootfs에 테스트 복사 후 실행 - CI 파이프라인에 셀프테스트 포함하여 자동 회귀 검사
일반적인 개발 워크플로
- 소스 다운로드
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git cd linux - 브랜치 생성
git checkout -b my-feature - 설정 및 빌드
make defconfig ./scripts/config --enable DEBUG_INFO make -j$(nproc) - 코드 탐색 인덱스 생성
make tags cscope ./scripts/clang-tools/gen_compile_commands.py - 코드 수정 및 테스트
# 에디터로 코드 수정 vim drivers/my_driver.c # 재빌드 make -j$(nproc) # QEMU 테스트 qemu-system-x86_64 -kernel arch/x86/boot/bzImage ... - 코딩 스타일 검사
./scripts/checkpatch.pl --file drivers/my_driver.c - 정적 분석
make C=2 drivers/my_driver.o - 패치 생성
git add drivers/my_driver.c git commit -s git format-patch -1
Git 커널 패치 워크플로 심화
리눅스 커널은 GitHub PR이 아닌 이메일 기반 패치 워크플로를 사용합니다. git format-patch, git send-email, b4 도구를 익히면 업스트림 기여가 가능해집니다.
패치 생성 (git format-patch)
# 마지막 커밋 1개를 패치로 생성
git format-patch -1
# 마지막 3개 커밋을 패치 시리즈로 생성
git format-patch -3 --cover-letter
# 특정 브랜치와의 차이를 패치로 생성
git format-patch origin/master..HEAD
# 버전 표시 (v2, v3 등 재전송 시)
git format-patch -1 -v 2
# 패치 출력 디렉토리 지정
git format-patch -3 -o patches/
패치 전송 (git send-email)
# git send-email 설치
sudo apt install git-email
# Git 이메일 설정
git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser your-email@gmail.com
git config --global sendemail.from "Your Name <your-email@gmail.com>"
# 패치를 메인테이너에게 전송
# get_maintainer.pl로 수신자 자동 결정
git send-email \
--to=$(./scripts/get_maintainer.pl --nogit --norolestats 0001-*.patch | head -1) \
--cc=linux-kernel@vger.kernel.org \
0001-my-patch.patch
# 패치 시리즈 전송 (커버 레터 포함)
git send-email \
--to=maintainer@kernel.org \
--cc=linux-kernel@vger.kernel.org \
patches/*.patch
메인테이너 & 리뷰어 찾기
# 파일별 메인테이너 찾기
./scripts/get_maintainer.pl -f drivers/net/ethernet/intel/e1000e/netdev.c
# 패치에 대한 메인테이너 찾기
./scripts/get_maintainer.pl 0001-my-patch.patch
# 특정 서브시스템의 메인테이너 트리 확인
grep -A5 "NETWORKING" MAINTAINERS
b4 패치 관리 도구
b4는 커널 메일링 리스트에서 패치 시리즈를 가져오고 적용하는 현대적 도구입니다.
# b4 설치
pip3 install b4
# 메일링 리스트에서 패치 시리즈 다운로드 (Message-ID로)
b4 am <message-id>
# 다운로드한 패치를 적용
git am *.mbx
# 패치 시리즈 정보 조회
b4 patchwork <message-id>
# b4로 패치 전송 준비
b4 prep --fork-point origin/master
b4 prep --edit-cover
b4 send
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
- 제목:
subsystem: 변경 요약(50자 이내, 마침표 없음) - 본문: 왜 변경이 필요한지 설명 (72자/줄)
- Signed-off-by: DCO(Developer Certificate of Origin) 동의 필수 (
git commit -s) - Fixes: 버그 수정 시 원인 커밋 SHA 참조
- Cc: stable 백포트 요청 시
Cc: stable@vger.kernel.org
트러블슈팅 플레이북
아래 순서대로 점검하면 환경 문제를 빠르게 축소할 수 있습니다. 핵심은 문제 범위를 한 단계씩 좁히는 것입니다.
- 도구 문제 분리:
gcc --version,make --version,ld --version - 설정 문제 분리:
make mrproper && make defconfig로 최소 상태 확인 - 소스 문제 분리: 같은 커밋을 깨끗한 트리에서 다시 빌드
- 런타임 문제 분리: QEMU에서 재현되는지 먼저 확인
- 디버깅 단계 진입: GDB 브레이크포인트와 부팅 로그를 함께 확보
| 오류 메시지 예시 | 우선 점검 | 대응 |
|---|---|---|
No rule to make target ... |
빌드 트리 오염 여부 | make mrproper 후 defconfig부터 재시작 |
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), 커밋 해시를 항상 함께 보관하세요.
이 네 가지가 있으면 대부분의 환경 문제를 재현하고 분석할 수 있습니다.
고급 트러블슈팅
| 오류 메시지 / 증상 | 원인 | 해결 |
|---|---|---|
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 |
버퍼 오버플로 감지 | 보고된 스택 트레이스에서 접근 위치 확인 후 경계 검사 추가 |
LOCKDEP possible circular locking |
데드락 위험 감지 | 락 획득 순서 재검토, 보고된 체인 분석 |
Kernel panic - not syncing: Attempted to kill init! |
PID 1(init) 프로세스 종료 | 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)"
추가 팁
git worktree를 사용하면 편리합니다.
git worktree add ../linux-stable stable
git worktree add ../linux-next next
./scripts/config --enable BLK_DEV_INITRD
make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -append "console=ttyS0" -nographic
Docker/Podman 컨테이너 개발 환경
컨테이너 기반 개발 환경은 호스트 시스템을 오염시키지 않으면서 재현 가능한 빌드 환경을 제공합니다. 팀 전체가 동일한 툴체인 버전을 사용하도록 강제할 수 있어, "내 머신에서는 빌드되는데" 문제를 완전히 차단합니다.
컨테이너 개발의 장점
| 항목 | 호스트 직접 설치 | 컨테이너 환경 |
|---|---|---|
| 재현성 | 호스트 업데이트에 따라 깨질 수 있음 | 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 \
libelf-dev libssl-dev \
bc libncurses-dev \
cpio rsync kmod \
dwarves sparse ccache \
\
# 코드 탐색
universal-ctags cscope \
clangd-18 clang-18 lld-18 llvm-18 \
\
# 가상화 & 디버깅
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/*
# 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
- 소스 코드: 호스트의 커널 소스를 바인드 마운트 → 에디터는 호스트에서, 빌드는 컨테이너에서
- 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:
- UID 매핑: 컨테이너 내부 UID와 호스트 UID가 다르면 소스 파일 권한 문제 발생 →
--build-arg UID=$(id -u)사용 - 빌드 산출물 소유권: 컨테이너에서 생성한 파일의 소유자가 호스트와 다를 수 있음 → Podman의
--userns=keep-id권장 - SELinux: Fedora/RHEL에서는 바인드 마운트에
:Z접미사 필요
원격 개발 환경
커널 개발은 고성능 머신이 필요하므로, 원격 서버에서 빌드하고 로컬에서 편집하는 패턴이 흔합니다. SSH, tmux, VS Code Remote를 활용하면 원격 환경에서도 쾌적한 개발이 가능합니다.
SSH 설정 최적화
# ~/.ssh/config
# 커널 빌드 서버
Host kernel-build
HostName 192.168.1.100
User kdev
Port 22
IdentityFile ~/.ssh/id_ed25519
# 연결 유지
ServerAliveInterval 60
ServerAliveCountMax 3
# 멀티플렉싱 (연결 재사용)
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
# 압축
Compression yes
# GDB 포트 포워딩
LocalForward 1234 localhost:1234
tmux 기본 설정
원격 환경에서 tmux는 필수입니다. SSH 연결이 끊어져도 빌드가 계속 실행되며, 여러 터미널을 동시에 관리할 수 있습니다.
# ~/.tmux.conf
# 커널 개발 전용 설정
set -g default-terminal "screen-256color"
set -g history-limit 50000
set -g mouse on
# 프리픽스 키 변경 (선택)
set -g prefix C-a
unbind C-b
bind C-a send-prefix
# 창 분할 키 바인딩
bind | split-window -h
bind - split-window -v
# 상태바에 호스트명 표시
set -g status-left "[#S@#H] "
set -g status-right "%H:%M %d-%b"
# 커널 개발 세션 스크립트
#!/bin/bash
# kernel-tmux.sh - 커널 개발 tmux 세션 자동 생성
SESSION="kernel"
LINUX_DIR="$HOME/linux"
tmux new-session -d -s $SESSION -c $LINUX_DIR
# 윈도우 0: 에디터
tmux rename-window -t $SESSION:0 "edit"
tmux send-keys -t $SESSION:0 "vim ." C-m
# 윈도우 1: 빌드
tmux new-window -t $SESSION -n "build" -c $LINUX_DIR
# 윈도우 2: QEMU (수평 분할)
tmux new-window -t $SESSION -n "qemu" -c $LINUX_DIR
tmux split-window -h -t $SESSION:2 -c $LINUX_DIR
# 왼쪽: QEMU 실행, 오른쪽: GDB 연결
# 윈도우 3: 로그 & 모니터링
tmux new-window -t $SESSION -n "logs" -c $LINUX_DIR
tmux select-window -t $SESSION:1
tmux attach -t $SESSION
VS Code Remote Development
VS Code의 Remote-SSH 확장을 사용하면 로컬에서 편집하면서 원격 서버의 clangd, 빌드 시스템을 그대로 활용할 수 있습니다.
// 원격 서버의 .vscode/settings.json
{
"remote.SSH.remotePlatform": {
"kernel-build": "linux"
},
"clangd.path": "/usr/bin/clangd-18",
"clangd.arguments": [
"--background-index",
"--clang-tidy",
"--completion-style=detailed",
"-j=4"
],
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/build/**": true
},
// 빌드 태스크
"tasks.version": "2.0.0"
}
// .vscode/tasks.json - 커널 빌드 태스크
{
"version": "2.0.0",
"tasks": [
{
"label": "Kernel Build",
"type": "shell",
"command": "make -j$(nproc)",
"group": { "kind": "build", "isDefault": true },
"problemMatcher": "$gcc"
},
{
"label": "Kernel Boot (QEMU)",
"type": "shell",
"command": "qemu-system-x86_64 -kernel arch/x86/boot/bzImage -append 'console=ttyS0 nokaslr' -nographic -enable-kvm -m 2G -s -S",
"isBackground": true
},
{
"label": "checkpatch",
"type": "shell",
"command": "./scripts/checkpatch.pl --file ${file}",
"problemMatcher": []
}
]
}
- SSH 멀티플렉싱:
ControlMaster auto로 연결 재사용 → VS Code 재연결 속도 대폭 향상 - 파일 감시 제외:
.git/objects,build/디렉토리를 감시 대상에서 제외하여 CPU 절약 - GDB 포트 포워딩: SSH config에
LocalForward 1234설정 → 로컬 VS Code에서 원격 QEMU에 GDB 연결 - tmux + SSH: 장시간 빌드 시 SSH 끊김에도 빌드 계속 진행
커널 설정 전략 심화
커널 설정(.config)은 4000개 이상의 옵션으로 구성됩니다. 목적에 맞는 설정 전략을 세우면 빌드 시간 단축과 디버깅 효율 향상을 동시에 달성할 수 있습니다.
설정 도구 비교
| 명령 | 인터페이스 | 의존성 | 특징 |
|---|---|---|---|
make menuconfig |
ncurses TUI | libncurses-dev |
가장 보편적, 검색(/) 지원 |
make nconfig |
ncurses TUI (개선판) | libncurses-dev |
향상된 검색, F1~F9 키 |
make xconfig |
Qt5 GUI | qtbase5-dev |
트리 뷰, 의존성 시각화 |
make gconfig |
GTK GUI | libgtk-3-dev |
GTK 기반 대안 |
make oldconfig |
CLI (질문) | 없음 | 기존 .config에 새 옵션만 질문 |
make olddefconfig |
CLI (자동) | 없음 | 새 옵션은 기본값으로 자동 설정 |
./scripts/config |
CLI (스크립트) | 없음 | 개별 옵션 enable/disable, 자동화에 적합 |
목적별 설정 전략
설정 프래그먼트 관리
프로젝트별 설정 변경을 .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로 베이스 + 프래그먼트 조합 자동화
참고자료
- HOWTO do Linux kernel development — 공식 커널 개발 가이드
- Development tools — 커널 개발 도구 문서
- Debugging kernel with GDB — GDB 디버깅 공식 가이드
- QEMU Documentation — QEMU 공식 문서
- clangd — clangd 공식 사이트
- ccache — ccache 공식 사이트
- KASAN — Kernel Address Sanitizer 공식 문서
- KCSAN — Kernel Concurrency Sanitizer 공식 문서
- ftrace — ftrace 공식 문서
- kselftest — 커널 셀프테스트 공식 문서
- Submitting patches — 패치 제출 가이드
- Linux kernel coding style — 코딩 스타일 가이드
- virtme-ng — 빠른 커널 테스트 도구
- perf Examples — Brendan Gregg의 perf 활용 예제
- Clang Cross Compilation — LLVM 크로스 컴파일 가이드
- 커널 빌드 시스템 — 본 사이트 관련 문서
- 디버깅 — 본 사이트 관련 문서
- 개발 도구 — 본 사이트 관련 문서
- 커널 보안 — 본 사이트 관련 문서
관련 문서
- 커널 개발 주의사항 — 리눅스 커널 개발 시 흔히 발생하는 실수와 주의사항, 해결 방법을 정리. 동기화 오류, 메
- 소스 코드 읽기 — ctags, cscope, clangd, git 활용, 함수 추적
- 코딩 스타일 — checkpatch.pl, 들여쓰기, 네이밍, 매크로 규칙