Linux Kernel은 단순히 gcc 명령 한 번으로 컴파일되는 프로그램이 아닙니다. 수만 개의 소스 파일과 수천 개의 설정 옵션을 바탕으로 여러 단계의 빌드 과정을 거쳐 최종 커널 이미지가 생성됩니다.
커널 개발자나 시스템 엔지니어라면 make menuconfig, make, vmlinux, bzImage, System.map, initramfs 같은 용어를 자주 접하게 됩니다. 각각은 커널 빌드 과정에서 중요한 역할을 담당합니다.
이번 글에서는 커널 컴파일이 어떤 순서로 진행되는지, 각 단계에서 어떤 파일이 생성되고 어떤 작업이 수행되는지 자세히 알아보겠습니다.
Linux Kernel 컴파일 과정이란?
커널 컴파일은 커널 소스 코드와 설정 파일(.config)을 기반으로 실행 가능한 커널 이미지를 생성하는 과정입니다.
전체 흐름은 다음과 같습니다.
Kernel Source
↓
.config
↓
Kconfig
↓
Make
↓
Compile
↓
Link
↓
vmlinux
↓
bzImage
↓
Install
이 과정에서 다양한 중간 파일과 최종 결과물이 생성됩니다.
전체 빌드 순서
커널 빌드는 일반적으로 다음 순서로 진행됩니다.
- 환경 준비
- 커널 설정
- 의존성 확인
- 소스 컴파일
- 오브젝트 링크
- vmlinux 생성
- bzImage 생성
- 모듈 생성
- 설치
각 단계는 서로 긴밀하게 연결되어 있습니다.
1단계. 커널 설정
먼저 .config 파일을 생성하거나 수정합니다.
대표 명령어
make menuconfig
또는
make defconfig
.config에는 다음과 같은 설정이 저장됩니다.
CONFIG_SMP=y
CONFIG_EXT4_FS=y
CONFIG_BPF=y
CONFIG_XDP_SOCKETS=y
이 설정에 따라 어떤 기능을 포함할지 결정됩니다.
2단계. Kconfig 분석
빌드 시스템은 .config를 읽어 필요한 기능을 확인합니다.
.config
↓
Kconfig
↓
Dependency Check
예를 들어 특정 드라이버가 다른 기능에 의존한다면 자동으로 함께 활성화되거나 비활성화됩니다.
3단계. Makefile 처리
커널 루트에는 최상위 Makefile이 존재합니다.
Makefile
↓
arch/
↓
drivers/
↓
fs/
↓
net/
↓
mm/
각 디렉터리의 Makefile을 읽으며 필요한 소스를 결정합니다.
4단계. 헤더 생성
컴파일 전에 다양한 헤더 파일이 생성됩니다.
예를 들어
include/generated/
디렉터리에는
- autoconf.h
- compile.h
- utsrelease.h
등이 생성됩니다.
이 파일들은 현재 커널 설정 정보를 담고 있습니다.
5단계. 소스 컴파일
각 C 파일은 오브젝트 파일(.o)로 변환됩니다.
kernel/sched/core.c
↓
core.o
컴파일 명령은 내부적으로 다음과 비슷한 형태로 실행됩니다.
gcc -c core.c -o core.o
실제로는 다양한 최적화 옵션과 커널 전용 옵션이 함께 사용됩니다.
6단계. 오브젝트 링크
생성된 수천 개의 오브젝트 파일을 하나로 연결합니다.
core.o
↓
mm.o
↓
fs.o
↓
drivers.o
↓
Link
이 과정을 통해 하나의 실행 가능한 커널이 만들어집니다.
7단계. vmlinux 생성
링크가 완료되면 vmlinux가 생성됩니다.
Object Files
↓
Link
↓
vmlinux
vmlinux는 압축되지 않은 ELF 형식의 커널 이미지입니다.
디버깅과 분석에 주로 사용됩니다.
8단계. bzImage 생성
실제로 부팅에 사용하는 이미지는 bzImage입니다.
vmlinux
↓
Compression
↓
bzImage
압축을 통해 크기를 줄이고 부팅 가능한 형태로 변환합니다.
일반적으로 다음 위치에 생성됩니다.
arch/x86/boot/bzImage
9단계. Kernel Module 생성
모듈도 함께 빌드됩니다.
drivers/
↓
*.ko
대표 결과물
- e1000e.ko
- ext4.ko
- xfs.ko
등 다양한 모듈이 생성됩니다.
10단계. 설치
빌드가 끝나면 커널을 설치합니다.
sudo make modules_install
sudo make install
설치 후 /boot 디렉터리에 다음 파일이 생성됩니다.
vmlinuz
System.map
config
initrd.img
컴파일 중 생성되는 주요 파일
| 파일 | 설명 |
|---|---|
| .config | 커널 설정 |
| vmlinux | 압축되지 않은 커널 |
| bzImage | 부팅용 커널 이미지 |
| System.map | 심볼 테이블 |
| Module.symvers | 모듈 심볼 정보 |
| *.ko | 커널 모듈 |
| include/generated | 자동 생성 헤더 |
이 파일들은 커널 개발과 디버깅에 매우 중요합니다.
병렬 컴파일
CPU 코어를 모두 활용하면 빌드 속도를 크게 높일 수 있습니다.
make -j$(nproc)
예를 들어 16코어 CPU라면 16개의 작업을 동시에 수행합니다.
빌드 로그 확인
빌드 중 오류가 발생하면 로그를 확인합니다.
make V=1
보다 자세한 컴파일 명령을 출력하여 문제를 분석할 수 있습니다.
실무에서 자주 사용하는 명령어
커널 설정
make menuconfig
기본 설정 생성
make defconfig
커널 컴파일
make -j$(nproc)
모듈 컴파일
make modules
모듈 설치
sudo make modules_install
커널 설치
sudo make install
빌드 로그 상세 출력
make V=1
실무 사례
예를 들어 네트워크 드라이버를 수정했다고 가정해 보겠습니다.
실무에서는 다음과 같은 순서로 작업합니다.
.config에서 해당 드라이버 활성화make menuconfig로 설정 확인make -j$(nproc)로 전체 커널 빌드drivers/net/의 수정 내용이.o파일로 컴파일- 새로운
vmlinux와bzImage생성 make modules_install및make install실행- 재부팅 후 수정된 드라이버 동작 확인
이처럼 커널 컴파일은 단순한 빌드가 아니라 설정, 컴파일, 링크, 설치까지 포함하는 전체 개발 과정입니다.
자주 묻는 질문
vmlinux와 bzImage의 차이는 무엇인가요?
vmlinux는 압축되지 않은 ELF 형식의 커널 이미지로 주로 디버깅과 분석에 사용됩니다. bzImage는 vmlinux를 압축하여 만든 실제 부팅용 커널 이미지입니다.
커널을 수정하면 항상 전체를 다시 컴파일해야 하나요?
대부분은 필요한 부분만 다시 컴파일할 수 있지만, 핵심 커널 코드나 설정을 변경한 경우에는 전체 빌드를 수행하는 것이 일반적입니다.
make -j 옵션은 어떤 역할을 하나요?
-j 옵션은 여러 CPU 코어를 사용하여 병렬로 컴파일하는 기능입니다. 코어 수가 많을수록 전체 빌드 시간을 크게 단축할 수 있습니다.
마무리
Linux Kernel 컴파일은 .config 설정부터 vmlinux 생성, bzImage 압축, 모듈 생성과 설치까지 여러 단계를 거쳐 진행됩니다. 각 단계의 역할과 생성 파일을 이해하면 커널 개발과 디버깅이 훨씬 수월해지며, 문제 발생 시 원인을 빠르게 파악할 수 있습니다. 커널 개발을 시작하는 개발자라면 전체 빌드 과정을 반드시 이해하고 있어야 합니다.